Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

nixpi

nixpi declaratively configures the Pi coding agent with Nix. It provides one typed programs.pi module for standalone packages, Home Manager, NixOS, and nix-darwin.

Start here

Run the default agent without creating a configuration:

nix run github:mateusdcc/nixpi

For a project or personal configuration, start from a template, then read the usage guide. The complete option reference is generated from the live Nix module schema during every documentation build, so it includes every programs.pi option, type, default, and description.

What is documented

  • Every public flake output and library function, with callable examples.
  • Every programs.pi option, generated from the evaluated module.
  • Bundled profiles, extensions, skills, and providers.
  • Home Manager, NixOS, nix-darwin, standalone, devShell, and direnv usage.
  • Templates, secrets, mutable state, updating, tests, migration guidance, and troubleshooting.

The site is built by nix build .#docs. Its static files are in result/share/doc/nixpi/html and GitHub Actions publishes that same directory to GitHub Pages.

Getting started

Run the default package

nix run github:mateusdcc/nixpi

The default package includes a declarative configuration with safe defaults. Pin the input in a flake for repeatable installations.

Home Manager

Add the input and import the module:

{
  inputs.nixpi.url = "github:mateusdcc/nixpi";

  outputs = { home-manager, nixpkgs, nixpi, ... }: {
    homeConfigurations.me = home-manager.lib.homeManagerConfiguration {
      pkgs = nixpkgs.legacyPackages.aarch64-darwin;
      modules = [
        nixpi.homeModules.default
        {
          home = {
            username = "me";
            homeDirectory = "/Users/me";
            stateVersion = "26.05";
          };
          programs.pi = {
            enable = true;
            settings.defaultProvider = "openai";
            extensions.ripgrep-search.enable = true;
            skills.commit-style.enable = true;
            environment.required = [ "OPENAI_API_KEY" ];
          };
        }
      ];
    };
  };
}

Use nixpi.nixosModules.default in NixOS and nixpi.nixDarwinModules.default in nix-darwin. The programs.pi options are shared by every integration.

Secrets

Do not put secret values in Nix expressions. Declare only their names with programs.pi.environment.required, then provide values through the runtime environment. The wrapper reports missing names before Pi starts.

Updating safely

Commit flake.lock, review deprecation warnings, and run nix flake check before switching a system. Existing 1.x output names remain available with warnings throughout the 1.x release line.

Everyday usage

Choose an integration

Use the same programs.pi options in every integration. The difference is where the evaluated package is installed.

SituationEntry pointRun it
One-off trialpackages.<system>.defaultnix run github:mateusdcc/nixpi
Project-owned agentlib.nixpi.makePinix run .#
User environmenthomeModules.defaultactivate Home Manager
NixOS hostnixosModules.defaultrebuild NixOS
macOS hostnixDarwinModules.defaultrebuild nix-darwin

Standalone package

This is the smallest persistent configuration. Put it in a project flake.nix, replace the system value when needed, and keep flake.lock committed.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-26.05";
    nixpi.url = "github:mateusdcc/nixpi";
  };

  outputs = { nixpkgs, nixpi, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in {
      packages.${system}.default = nixpi.lib.nixpi.makePi {
        inherit pkgs;
        modules = [{
          programs.pi = {
            enable = true;
            settings = {
              defaultProvider = "openai";
              defaultModel = "gpt-4o";
            };
            extensions.ripgrep-search.enable = true;
            skills.commit-style.enable = true;
            environment.required = [ "OPENAI_API_KEY" ];
          };
        }];
      };
    };
}

Run it with nix run .#. environment.required checks that a name exists at launch time. It does not put secret values in the Nix store.

Home Manager

Import nixpi.homeModules.default, then configure the same module namespace:

{
  imports = [ inputs.nixpi.homeModules.default ];

  programs.pi = {
    enable = true;
    settings.defaultProvider = "anthropic";
    extensions.plan-mode = {
      enable = true;
      mode = "balanced";
    };
    environment.required = [ "ANTHROPIC_API_KEY" ];
  };
}

The integration installs the evaluated package and links the generated immutable settings.json and, when configured, models.json under ~/.pi/agent.

NixOS and nix-darwin

Import inputs.nixpi.nixosModules.default in NixOS or inputs.nixpi.nixDarwinModules.default in nix-darwin. Configure programs.pi exactly as above. The option schema and generated package are shared across all three host integrations.

Secrets and state

Put only non-secret values in environment.variables. Export API keys from your shell, your secret manager, or your host configuration before starting Pi. auth.json and sessions/ remain mutable runtime state.

programs.pi.environment = {
  variables.PI_OFFLINE = "1";
  required = [ "OPENAI_API_KEY" ];
};

Do not write API key values into a Nix expression. Nix derivations and their logs can be world-readable to users of the same store.

direnv

direnv is a convenient way to give a repository a reproducible Pi command and expose secret names only while you are in that repository.

Project flake

Start with the devshell template or add this output to an existing flake:

devShells.${system}.default = pkgs.mkShell {
  packages = [
    (nixpi.lib.nixpi.makePi {
      inherit pkgs;
      modules = [{
        programs.pi = {
          enable = true;
          settings.defaultProvider = "openai";
          extensions.ripgrep-search.enable = true;
          environment.required = [ "OPENAI_API_KEY" ];
        };
      }];
    })
  ];
};

.envrc

Keep secrets outside Git. One simple pattern is a local .envrc that reads a separately ignored file and enters the flake development shell:

dotenv_if_exists .env.local
use flake

Put the real value in .env.local, which must be ignored:

export OPENAI_API_KEY='replace-with-your-secret-manager-output'

Then allow the project once:

direnv allow
pi

Why this works

use flake adds the configured Pi package to PATH. nixpi evaluates the required variable names into the launcher but does not evaluate their values. The launcher verifies that OPENAI_API_KEY is present only when you start Pi.

For shared or production credentials, have .envrc call your existing secret manager instead of storing a value in .env.local.

Templates

Initialize a new directory with the template that matches how Pi will be used:

nix flake init --template github:mateusdcc/nixpi#standalone
TemplateCommand suffixUse it for
Standalone#standaloneA configured nix run .# agent package.
Home Manager#home-managerA home.nix fragment for a user installation.
devShell#devshellA repository development environment, especially with direnv.
learning#learningLegacy compatibility only. Use deep-comprehension-engine for new learning environments.

Standalone

After initializing, set the target system and provider in flake.nix, export the required key, and run:

nix run .#

Home Manager

The template supplies a home.nix module. Add it to your Home Manager module list after importing nixpi.homeModules.default:

modules = [
  inputs.nixpi.homeModules.default
  ./home.nix
];

devShell

Use this for a repository-specific agent and pair it with the direnv guide. Enter it manually with:

nix develop

The template makes Pi, Git, and ripgrep available in the shell. Change programs.pi in the template rather than maintaining a separate imperative setup script.

Configuration

All configuration lives under programs.pi. This page provides a map; use All options for the generated, exhaustive reference.

programs.pi = {
  enable = true;

  settings = {
    defaultProvider = "openai";
    defaultModel = "gpt-4o";
    defaultThinkingLevel = "medium";
    theme = "dark";
  };

  extensions = {
    echo.enable = true;
    ripgrep-search.enable = true;
    plan-mode.enable = true;
  };

  skills.commit-style.enable = true;

  providers.local = {
    baseUrl = "http://localhost:11434/v1";
    models = [{ id = "local-model"; }];
  };

  runtimePackages = with pkgs; [ git jq ];
  environment.required = [ "OPENAI_API_KEY" ];
};

Main sections

SectionPurpose
settingsPi settings serialized into the generated settings file.
providersProvider endpoints, package support, models, and credentials references.
extensionsEnable packaged extensions and provide extension-specific settings.
skillsEnable skill packages that Pi can discover.
prompts and themesAdd prompt and theme resources.
runtimePackagesCommands available to Pi and extensions at runtime.
environmentNon-secret variables and required environment variable names.
resources and extraPackagesCompose custom resource and package inputs.

Add a local provider

programs.pi.providers.local = {
  baseUrl = "http://localhost:11434/v1";
  api = "openai-completions";
  models = [
    {
      id = "qwen2.5-coder";
      name = "Qwen 2.5 Coder";
    }
  ];
};

Add runtime tools

An extension that invokes git, rg, or a language runtime needs those executables in runtimePackages:

programs.pi.runtimePackages = with pkgs; [
  git
  ripgrep
  jq
  nodejs
];

The generated option reference documents the exact option type and default for each item.

Flake outputs

OutputPurpose
packages.<system>.defaultConfigured Pi executable
packages.<system>.legal-researchLegal research profile
packages.<system>.docsGenerated option and project documentation
packages.<linux-system>.docker-*Tested minimal, features, and provider CI images
piModules.defaultComplete standalone module
piModules.baseReusable core without bundled features
piModules.profiles.*Curated configurations
piModules.extensions.*Individual extension modules
piModules.skills.*Individual skill modules
piModules.providers.*Individual provider modules
homeModules.defaultHome Manager integration
nixosModules.defaultNixOS integration
nixDarwinModules.defaultnix-darwin integration
lib.nixpiCanonical library namespace
overlays.defaultAdds packages under pkgs.nixpi
templates.*Starter flakes

Compatibility aliases such as homeManagerModules, piModules.core, and moved learning resources remain available during 1.x. Evaluation emits a warning that identifies the replacement.

The complete generated option reference is available from:

nix build .#docs

Open result/share/doc/nixpi/options.md after the build.

Library API

The public library is nixpi.lib.nixpi. Builder functions accept pkgs either as an argument in their input set or through the extensible library used by nixpi itself.

Evaluate and build

evalPi

evalPi { pkgs, modules ? [], extraSpecialArgs ? {} } evaluates the complete Pi module system and returns the normal Nix module evaluation result, including config and options.

let
  evaluated = nixpi.lib.nixpi.evalPi {
    inherit pkgs;
    modules = [{ programs.pi.enable = true; }];
  };
in evaluated.config.programs.pi.finalPackage

makePi

makePi { pkgs, modules ? [], extraSpecialArgs ? {} } returns the configured Pi package. Its passthru exposes config, options, unwrapped, and extend.

let
  pi = nixpi.lib.nixpi.makePi {
    inherit pkgs;
    modules = [{ programs.pi.enable = true; }];
  };
in pi.extend {
  programs.pi.skills.commit-style.enable = true;
}

Package resources

mkPiExtension

mkPiExtension { pname, src, version ? "0.1.0", runtimePackages ? [], runtimeEnvironment ? {}, piManifest ? {}, meta ? {}, ... } packages an extension directory. It writes a default Pi manifest if src does not provide package.json.

myExtension = nixpi.lib.nixpi.mkPiExtension {
  inherit pkgs;
  pname = "hello";
  src = pkgs.writeTextDir "extensions/index.js" ''
    export default pi => pi.registerCommand("hello", { handler: () => console.log("hello") });
  '';
};

mkPiSkill

mkPiSkill { name, description ? "", content ? "", src ? null, runtimePackages ? [], passthru ? {}, meta ? {} } creates a skill package. With src, it returns that source unchanged.

nixpi.lib.nixpi.mkPiSkill {
  inherit pkgs;
  name = "release-check";
  description = "Check a release before publishing.";
  content = "Run nix flake check before a release.";
}

mkPiPrompt

mkPiPrompt { name, description ? "", argumentHint ? null, content } creates a prompt Markdown resource, adding front matter when requested.

nixpi.lib.nixpi.mkPiPrompt {
  inherit pkgs;
  name = "review";
  argumentHint = "[path]";
  content = "Review the requested path for correctness and maintainability.";
}

mkPiTheme

mkPiTheme { name, colors } creates a JSON theme resource. name is added to the supplied color attribute set.

nixpi.lib.nixpi.mkPiTheme {
  inherit pkgs;
  name = "night";
  colors.background = "#111827";
}

mkPiProvider

mkPiProvider { name, src ? null, package ? null, version ? "0.1.0", baseUrl ? null, api ? null, apiKey ? null, models ? {}, runtimePackages ? [], environment ? {}, piManifest ? {}, meta ? {}, ... } returns a normalized provider object. models may be a list or attribute set. A src is packaged as an extension when no package is supplied.

nixpi.lib.nixpi.mkPiProvider {
  inherit pkgs;
  name = "local";
  baseUrl = "http://localhost:11434/v1";
  models = [{ id = "qwen2.5-coder"; }];
}

Module factories

mkPiExtensionModule

Creates a complete programs.pi.extensions.<name> module. It accepts name, optional description, package or defaultPackage, runtimePackages, extraPackages, settingsOptions, settingsExample, settingsDescription, defaultText, extraOptions, and extraConfig.

nixpi.lib.nixpi.mkPiExtensionModule {
  name = "hello";
  defaultPackage = myExtension;
  runtimePackages = [ pkgs.git ];
}

mkPiSkillModule

Creates a complete programs.pi.skills.<name> module. It accepts name, optional description, package or defaultPackage, runtimePackages, extraPackages, defaultText, extraOptions, and extraConfig.

nixpi.lib.nixpi.mkPiSkillModule {
  name = "release-check";
  defaultPackage = mySkill;
}

mkPiProviderModule

Creates a complete programs.pi.providers.<name> module. It accepts name, optional description, package or defaultPackage, baseUrl, api, apiKey, models, runtimePackages, extraPackages, and extraConfig.

nixpi.lib.nixpi.mkPiProviderModule {
  name = "local";
  baseUrl = "http://localhost:11434/v1";
  models = [{ id = "qwen2.5-coder"; }];
}

deprecation.warn

deprecation.warn { old, replacement, supportedThrough ? "1.x" } value returns value while emitting a Nix evaluation warning. It is used for compatibility aliases.

nixpi.lib.nixpi.deprecation.warn {
  old = "oldOutput";
  replacement = "newOutput";
} value

Bundled modules

Import the complete module with nixpi.piModules.default, or import a focused module from the output names below. The generated option reference is authoritative for every option exposed by these modules.

Core and profiles

OutputPurpose
piModules.baseCore options without bundled features.
piModules.defaultCore plus the bundled feature modules.
piModules.profiles.minimalMinimal Pi configuration.
piModules.profiles.researchResearch-oriented configuration.
piModules.profiles.legalResearchLegal research configuration.

piModules.profiles.learning remains a deprecated compatibility alias for deep-comprehension-engine.

Extensions

OutputEnable withUse
piModules.extensions.echoextensions.echo.enable = true;Simple command extension and package example.
piModules.extensions.ripgrep-searchextensions.ripgrep-search.enable = true;Repository search using ripgrep.
piModules.extensions.plan-modeextensions.plan-mode.enable = true;Planning workflow controls.
piModules.extensions.pi-gpt-searchextensions.pi-gpt-search.enable = true;GPT-powered search integration.
piModules.extensions.researchToolsextensions.research-tools.enable = true;Research tools and MCP bridges.

piModules.extensions.obsidian is a deprecated compatibility alias. Configure the replacement from deep-comprehension-engine for new work.

Skills

Enable a bundled skill through programs.pi.skills:

programs.pi.skills = {
  commit-style.enable = true;
  legal-pain-discovery.enable = true;
  voice-of-customer-mining.enable = true;
  evidence-deduplication.enable = true;
  legal-market-segmentation.enable = true;
  competitor-gap-analysis.enable = true;
  brazil-localization-test.enable = true;
  opportunity-scoring.enable = true;
  product-opportunity-report.enable = true;
};

The corresponding public module outputs are commit-style, legalPainDiscovery, voiceOfCustomerMining, evidenceDeduplication, legalMarketSegmentation, competitorGapAnalysis, brazilLocalizationTest, opportunityScoring, and productOpportunityReport under piModules.skills.

The former learning skills under piModules.skills are compatibility aliases that warn and point to deep-comprehension-engine.

Providers

piModules.providers.antigravity adds the Antigravity provider module. It can be enabled through the normal programs.pi.providers.antigravity option tree. Use the provider’s generated options for models, endpoint, package, and credential requirements.

Host modules

OutputAliasUse
homeModules.defaulthomeModules.pi, homeManagerModulesHome Manager.
nixosModules.defaultnixosModules.piNixOS.
nixDarwinModules.defaultnixDarwinModules.pinix-darwin.

All options

programs.pi.enable

Whether to enable Pi coding agent.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.package

The base Pi coding agent package to use.

Type: package

Default:

pkgs.pi-coding-agent

Declared by:

programs.pi.packages

List of Pi packages (derivations or directory paths) to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.assertions

List of assertions to check during evaluation.

Type: list of unspecified value

Default:

[ ]

Declared by:

programs.pi.builtinProviders

List of built-in LLM providers.

Type: list of string (read only)

Default:

[
  "antigravity"
  "openai"
  "anthropic"
  "google"
  "ollama"
  "openrouter"
  "groq"
  "deepseek"
  "mistral"
  "bedrock"
  "xai"
  "github-models"
  "copilot"
  "azure-openai"
  "cerebras"
  "together"
  "fireworks"
  "cohere"
]

Declared by:

programs.pi.environment.optional

List of optional environment variable names supported by the configuration.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.environment.required

List of environment variable names required by enabled extensions or providers. These are checked or documented as runtime requirements.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.environment.variables

Non-secret environment variables to export for Pi. DO NOT put secret API keys here as they will be written into the Nix store.

Type: attribute set of (null or string or signed integer or boolean or absolute path)

Default:

{ }

Declared by:

programs.pi.extensions.echo.enable

Whether to enable Pi echo extension.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.extensions.echo.package

Package providing the echo extension.

Type: package

Default:

pkgs.piExtensions.echo

Declared by:

programs.pi.extensions.pi-gpt-search.enable

Whether to enable Pi GPT search extension (OpenAI Codex search engine).

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.extensions.pi-gpt-search.package

Package providing the pi-gpt-search extension.

Type: package

Default:

pkgs.piExtensions.pi-gpt-search

Declared by:

programs.pi.extensions.pi-gpt-search.debug

Enable debug logging for web search operations.

Type: boolean

Default:

false

Declared by:

programs.pi.extensions.plan-mode.enable

Whether to enable Pi plan-mode extension.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.extensions.plan-mode.package

Package providing the plan-mode extension.

Type: package

Default:

pkgs.piExtensions.plan-mode

Declared by:

programs.pi.extensions.plan-mode.autoApprove

Whether to automatically approve plan steps.

Type: boolean

Default:

false

Declared by:

programs.pi.extensions.plan-mode.maxSteps

Maximum number of steps in plan execution.

Type: signed integer

Default:

10

Declared by:

programs.pi.extensions.plan-mode.mode

Planning execution mode.

Type: one of “fast”, “balanced”, “thorough”

Default:

"balanced"

Declared by:

programs.pi.extensions.research-tools.enable

Whether to enable Pi legal tech research tools & MCP bridge extension.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.extensions.research-tools.enableGptResearcher

Enable GPT Researcher synthesis fallback tool (conditional, disabled by default).

Type: boolean

Default:

false

Declared by:

programs.pi.extensions.research-tools.enableWorldMonitor

Enable World Monitor macro context tool (conditional, disabled by default).

Type: boolean

Default:

false

Declared by:

programs.pi.extensions.research-tools.enableXhs

Enable XHS / RedNote Chinese market research tool (conditional, disabled by default).

Type: boolean

Default:

false

Declared by:

programs.pi.extensions.research-tools.package

Package providing the research-tools extension.

Type: package

Default:

pkgs.piExtensions.research-tools

Declared by:

programs.pi.extensions.ripgrep-search.enable

Whether to enable Pi ripgrep-search extension.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.extensions.ripgrep-search.package

Package providing the ripgrep-search extension.

Type: package

Default:

pkgs.piExtensions.ripgrep-search

Declared by:

programs.pi.extraExtensions

Extra standalone extension file paths or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.extraPackages

Extra CLI packages to make available in PATH for Pi (alias/escape hatch for runtimePackages).

Type: list of package

Default:

[ ]

Declared by:

programs.pi.extraSkills

Extra standalone skill directory paths or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.finalPackage

The fully configured and wrapped Pi coding agent package.

Type: package (read only)

Declared by:

programs.pi.finalRuntimePackages

Combined list of all runtime packages from core, extensions, and derivations.

Type: list of package (read only)

Default:

[ ]

Declared by:

programs.pi.generatedModelsFile

Generated immutable models.json derivation (null if no providers defined).

Type: null or package (read only)

Default:

null

Declared by:

programs.pi.generatedSettingsFile

Generated immutable settings.json derivation.

Type: package (read only)

Declared by:

programs.pi.prompts

List of prompt template files or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.providers

Declared LLM providers with options and model definitions.

Type: attribute set of (open submodule of attribute set of anything)

Default:

{ }

Declared by:

programs.pi.providers.<name>.enable

Whether this provider is enabled.

Type: boolean

Default:

true

Declared by:

programs.pi.providers.<name>.package

Optional package/extension derivation implementing this provider.

Type: null or package

Default:

null

Declared by:

programs.pi.providers.<name>.packages

Additional packages implementing this provider.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.providers.<name>.api

API protocol type (e.g. openai-completions, anthropic-messages).

Type: null or string

Default:

null

Declared by:

programs.pi.providers.<name>.apiKey

API key or placeholder.

Type: null or string

Default:

null

Declared by:

programs.pi.providers.<name>.baseUrl

Base URL for the provider API endpoint.

Type: null or string

Default:

null

Declared by:

programs.pi.providers.<name>.environment

Environment variables and secret requirements for this provider.

Type: submodule

Default:

{ }

Declared by:

programs.pi.providers.<name>.environment.optional

Optional environment variable names.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.providers.<name>.environment.required

Required environment variable names.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.providers.<name>.environment.variables

Environment variables exported for this provider.

Type: attribute set of anything

Default:

{ }

Declared by:

programs.pi.providers.<name>.models

Models offered by this provider.

Type: (attribute set of (open submodule of attribute set of anything)) or (list of anything) convertible to it

Default:

{ }

Declared by:

programs.pi.providers.<name>.models.<name>.contextWindow

Maximum context window size in tokens.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.providers.<name>.models.<name>.id

Unique model identifier.

Type: string

Default:

"‹name›"

Declared by:

programs.pi.providers.<name>.models.<name>.maxTokens

Maximum output tokens.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.providers.<name>.models.<name>.name

Human-readable display name for the model.

Type: null or string

Default:

null

Declared by:

programs.pi.providers.<name>.models.<name>.reasoning

Whether the model supports extended reasoning/thinking.

Type: null or boolean

Default:

null

Declared by:

programs.pi.providers.<name>.name

Provider identifier.

Type: string

Default:

"‹name›"

Declared by:

programs.pi.providers.<name>.runtimePackages

Runtime dependencies added to PATH for this provider.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.rawExtensions

List of standalone extension file paths or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.rawSkills

List of standalone skill directory paths or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

programs.pi.runtimePackages

List of CLI packages to make available in PATH for Pi and its extensions.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.settings

Pi settings configuration (generated as settings.json).

Type: open submodule of attribute set of anything

Default:

{ }

Declared by:

programs.pi.settings.enableSkillCommands

Register skills as /skill:name commands.

Type: boolean

Default:

true

Declared by:

programs.pi.settings.enabledModels

Model patterns for Ctrl+P cycling.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.settings.compaction

Conversation compaction settings.

Type: null or (submodule)

Default:

null

Declared by:

programs.pi.settings.compaction.enabled

Enable auto-compaction.

Type: null or boolean

Default:

null

Declared by:

programs.pi.settings.compaction.keepRecentTokens

Recent tokens to keep without summarization.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.compaction.reserveTokens

Tokens reserved for LLM response.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.defaultModel

Default model ID to use (string ID or model object).

Type: (null or string) or (string or (attribute set)) convertible to it

Default:

null

Declared by:

programs.pi.settings.defaultProvider

Default LLM provider to use (string name or provider object).

Type: (null or string) or (string or (attribute set)) convertible to it

Default:

null

Declared by:

programs.pi.settings.defaultThinkingLevel

Default reasoning/thinking level.

Type: null or one of “off”, “minimal”, “low”, “medium”, “high”, “xhigh”, “max”

Default:

null

Declared by:

programs.pi.settings.npmCommand

Command argv used for npm package operations.

Type: null or (list of string)

Default:

null

Declared by:

programs.pi.settings.retry

Agent and provider retry settings.

Type: null or (submodule)

Default:

null

Declared by:

programs.pi.settings.retry.enabled

Enable automatic agent-level retry.

Type: null or boolean

Default:

null

Declared by:

programs.pi.settings.retry.baseDelayMs

Base delay for exponential backoff.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.retry.maxRetries

Maximum agent-level retry attempts.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.retry.provider

Provider-level retry configuration.

Type: null or (submodule)

Default:

null

Declared by:

programs.pi.settings.retry.provider.maxRetries

Provider/SDK retry attempts.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.retry.provider.maxRetryDelayMs

Max server-requested delay before failing.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.retry.provider.timeoutMs

Provider timeout in milliseconds.

Type: null or signed integer

Default:

null

Declared by:

programs.pi.settings.sessionDir

Directory for session storage and lookup.

Type: null or string

Default:

null

Declared by:

programs.pi.settings.theme

Name of the active theme.

Type: null or string

Default:

null

Declared by:

programs.pi.skills.brazil-localization-test.enable

Whether to enable Pi Brazil localization test skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.brazil-localization-test.package

Package providing the brazil-localization-test skill.

Type: null or package

Default:

<derivation pi-skill-brazil-localization-test-0.1.0>

Declared by:

programs.pi.skills.brazil-localization-test.runtimePackages

Additional runtime packages required by the brazil-localization-test skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.commit-style.enable

Whether to enable Pi commit-style skill (Conventional Commits v1.0.0).

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.commit-style.package

Package providing the commit-style skill.

Type: package

Default:

pkgs.piSkills.commit-style

Declared by:

programs.pi.skills.commit-style.customGuidelines

Additional guidelines or rules for writing commit messages.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.skills.commit-style.examples

Additional repository-specific commit examples.

Type: list of (string or (submodule))

Default:

[ ]

Declared by:

programs.pi.skills.commit-style.scopes

List of recommended or repository-specific scopes.

Type: list of string

Default:

[ ]

Declared by:

programs.pi.skills.commit-style.types

List of allowed commit types with descriptions.

Type: list of (string or (submodule))

Default:

[
  {
    description = "A new feature for the user or library (correlates with SemVer MINOR)";
    name = "feat";
  }
  {
    description = "A bug fix for the user or library (correlates with SemVer PATCH)";
    name = "fix";
  }
  {
    description = "Documentation changes only";
    name = "docs";
  }
  {
    description = "Code style/formatting changes that do not affect code logic or semantics";
    name = "style";
  }
  {
    description = "Refactoring production code (neither fixes a bug nor adds a feature)";
    name = "refactor";
  }
  {
    description = "A code change that improves performance";
    name = "perf";
  }
  {
    description = "Adding missing tests, refactoring tests, or correcting test fixtures";
    name = "test";
  }
  {
    description = "Changes that affect the build system or external dependencies (e.g. Nix, npm, Cargo)";
    name = "build";
  }
  {
    description = "Changes to CI/CD configuration files, scripts, and workflows (e.g. GitHub Actions)";
    name = "ci";
  }
  {
    description = "Routine maintenance tasks, tool configs, or auxiliary changes";
    name = "chore";
  }
  {
    description = "Reverts a previous commit";
    name = "revert";
  }
]

Declared by:

programs.pi.skills.competitor-gap-analysis.enable

Whether to enable Pi competitor gap analysis skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.competitor-gap-analysis.package

Package providing the competitor-gap-analysis skill.

Type: null or package

Default:

<derivation pi-skill-competitor-gap-analysis-0.1.0>

Declared by:

programs.pi.skills.competitor-gap-analysis.runtimePackages

Additional runtime packages required by the competitor-gap-analysis skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.evidence-deduplication.enable

Whether to enable Pi evidence deduplication skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.evidence-deduplication.package

Package providing the evidence-deduplication skill.

Type: null or package

Default:

<derivation pi-skill-evidence-deduplication-0.1.0>

Declared by:

programs.pi.skills.evidence-deduplication.runtimePackages

Additional runtime packages required by the evidence-deduplication skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.legal-market-segmentation.enable

Whether to enable Pi legal market segmentation skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.legal-market-segmentation.package

Package providing the legal-market-segmentation skill.

Type: null or package

Default:

<derivation pi-skill-legal-market-segmentation-0.1.0>

Declared by:

programs.pi.skills.legal-market-segmentation.runtimePackages

Additional runtime packages required by the legal-market-segmentation skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.legal-pain-discovery.enable

Whether to enable Pi legal pain discovery research skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.legal-pain-discovery.package

Package providing the legal-pain-discovery skill.

Type: null or package

Default:

<derivation pi-skill-legal-pain-discovery-0.1.0>

Declared by:

programs.pi.skills.legal-pain-discovery.runtimePackages

Additional runtime packages required by the legal-pain-discovery skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.opportunity-scoring.enable

Whether to enable Pi opportunity scoring skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.opportunity-scoring.package

Package providing the opportunity-scoring skill.

Type: null or package

Default:

<derivation pi-skill-opportunity-scoring-0.1.0>

Declared by:

programs.pi.skills.opportunity-scoring.runtimePackages

Additional runtime packages required by the opportunity-scoring skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.product-opportunity-report.enable

Whether to enable Pi product opportunity report skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.product-opportunity-report.package

Package providing the product-opportunity-report skill.

Type: null or package

Default:

<derivation pi-skill-product-opportunity-report-0.1.0>

Declared by:

programs.pi.skills.product-opportunity-report.runtimePackages

Additional runtime packages required by the product-opportunity-report skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.skills.voice-of-customer-mining.enable

Whether to enable Pi voice of customer mining skill.

Type: boolean

Default:

false

Example:

true

Declared by:

programs.pi.skills.voice-of-customer-mining.package

Package providing the voice-of-customer-mining skill.

Type: null or package

Default:

<derivation pi-skill-voice-of-customer-mining-0.1.0>

Declared by:

programs.pi.skills.voice-of-customer-mining.runtimePackages

Additional runtime packages required by the voice-of-customer-mining skill.

Type: list of package

Default:

[ ]

Declared by:

programs.pi.themes

List of theme JSON files or derivations to load.

Type: list of (package or absolute path or string)

Default:

[ ]

Declared by:

FAQ

Why are there files in both ~/.pi/agent and $XDG_DATA_HOME/nixpi/agent?

This is the concern raised in issue #3. It is not a configuration split. Home Manager links generated settings.json and models.json under ~/.pi/agent. The generated launcher sets PI_CODING_AGENT_DIR to its XDG runtime directory and links the same immutable generated configuration there before Pi starts.

Pi reads the directory selected by the launcher. The Home Manager links are useful as a conventional, inspectable location, but they are not a competing configuration source. auth.json and sessions/ remain writable runtime state.

Where should API keys go?

Outside Nix expressions. Export them from your shell, direnv, a secret manager, or host secret integration, then list only the variable names in programs.pi.environment.required. See direnv.

Why does nix build not show my new secret or session?

Those values are intentionally not build inputs. nixpi produces immutable configuration and a launcher. Credentials and session state are runtime data, so they are neither copied into the Nix store nor changed by rebuilds.

Which branch should I pin?

Pin main for the stable release channel or track specific version tags like v1.0.0. Pin the input deliberately in your flake.nix, commit flake.lock, and read warnings when updating. Use the versioned compatibility policy in the README and migration guide when moving older configurations.

How do I see every available option?

Open All options on this site. It is generated with nixosOptionsDoc from the evaluated programs.pi schema. Locally, run nix build .#docs and open result/share/doc/nixpi/options.md.

Can I use nixpi without Home Manager, NixOS, or nix-darwin?

Yes. Use lib.nixpi.makePi in a standalone flake, or initialize the standalone template. Run the resulting package with nix run .#.

How do I add an extension or skill that nixpi does not package?

Package it with mkPiExtension or mkPiSkill, then compose an option module with mkPiExtensionModule or mkPiSkillModule. The Library API includes each function signature and example.

Why did I get a deprecation warning?

The output or option is a supported 1.x compatibility alias. The warning names its replacement. Update to that replacement before the next major version, then run nix flake check to validate the migrated configuration.

Migrating to the edge architecture

The edge release reorganizes internals while preserving the 1.x public contract.

  • Use lib.nixpi for library helpers.
  • Use piModules.base for the complete reusable core.
  • Use homeModules.default, nixosModules.default, or nixDarwinModules.default for host integration.
  • Import learning and Obsidian resources directly from deep-comprehension-engine in new configurations.

Compatibility aliases

The previous helper names, piModules.core, homeManagerModules, learning profile, Obsidian extension, and moved learning skill packages remain available throughout 1.x. They emit evaluation warnings but preserve behavior.

Rollout checklist

  1. Update the nixpi input on a feature branch.
  2. Run nix flake check in the consuming configuration.
  3. Replace warned names with their documented replacements.
  4. Build the target Home Manager, NixOS, or nix-darwin configuration without activating it.
  5. Commit the updated lock file before activation.

Runtime secrets stay outside the Nix store. If environment.required is used, make sure those variables exist in the activation environment before starting Pi.

Security policy

Reporting a vulnerability

Use GitHub private vulnerability reporting for the repository. Do not open a public issue for suspected credential exposure, arbitrary code execution, unsafe generated shell, or a dependency vulnerability with a known exploit.

Include the affected revision, configuration, reproduction steps, impact, and any known mitigation. Maintainers should acknowledge a complete report within three business days and coordinate disclosure after a fix is available.

Supported versions

The latest stable release and the current edge release candidate receive security fixes. Older revisions may receive a backport when upgrading immediately would create a larger operational risk.

Security boundaries

nixpi generates packages, configuration files, and a runtime wrapper. Secret values must be supplied at runtime and must not be committed to Nix expressions, lock files, build logs, or store paths. Report any behavior that serializes secret values into the Nix store.

Architecture

nixpi separates stable contracts from implementation details.

Layers

  1. lib/ evaluates modules, builds packages, defines resource constructors, and owns deprecation helpers.
  2. modules/core/ defines the reusable programs.pi schema and package assembly.
  3. modules/extensions/, modules/skills/, and modules/providers/ add one capability each.
  4. modules/profiles/ composes capabilities into opinionated configurations.
  5. integrations/ maps the shared module into Home Manager, NixOS, and nix-darwin.
  6. flake/ publishes modules, packages, templates, checks, and legacy builders.

The root flake.nix only composes these output families. This keeps public contracts visible while preventing one file from owning unrelated concerns.

Dependency direction

Feature modules may depend on core options. Profiles may depend on feature modules. Integrations may depend on the complete module. Core modules must not depend on profiles or integrations.

Compatibility

Renames use helpers from lib/deprecation.nix. A deprecated output must continue to evaluate, identify its replacement, and have contract coverage. Breaking removals are reserved for a major release.

Verification

Unit-style evaluation tests cover option behavior. End-to-end tests execute the wrapped binary. Integration tests evaluate the project inside the real Home Manager, NixOS, and nix-darwin module systems. CI evaluates every supported system and builds on each platform family.

Container tests

nixpi builds its CI images directly with Nix. No imperative Dockerfile installation is involved, so the Pi package and scenario configuration use the same locked inputs as every other output.

Scenarios

ScenarioCoverage
minimalPi startup with no optional extensions or skills
featuresEcho, ripgrep search, plan mode, and commit-style skill
providerCustom OpenAI-compatible provider and required runtime secret

Each scenario has two checks:

  1. A flake check executes Pi and validates generated JSON with jq.
  2. Docker CI builds the image, loads it into Docker, verifies its scenario label, and runs the same test inside the container as an unprivileged user.

Docker CI runs every scenario on x86_64 Linux and ARM Linux.

Run locally on Linux

nix build .#docker-features
docker load < result
docker run --rm nixpi-ci-features:edge

Run only the configuration-level check with:

nix build .#checks.$(nix eval --impure --raw --expr builtins.currentSystem).container-features-tests

Contributing

Thank you for improving nixpi.

Before opening a change

  1. Check existing issues and pull requests for overlapping work.
  2. Discuss public API changes before implementation.
  3. Keep each change focused on one behavior or architectural concern.

Local checks

Use a recent Nix installation with flakes enabled:

nix fmt
nix flake check -L
nix flake check --all-systems --no-build -L

Add evaluation coverage for option changes, end-to-end coverage for runtime behavior, and real host integration coverage when Home Manager, NixOS, or nix-darwin behavior changes.

Design rules

  • Keep the public programs.pi schema shared across integrations.
  • Put reusable behavior in modules/core, one capability per feature module, and composition in profiles.
  • Preserve 1.x APIs with a deprecation warning and a tested compatibility alias.
  • Keep secrets out of Nix expressions and generated store paths.
  • Prefer direct Nix module composition over custom framework machinery.

Commits and pull requests

Use Conventional Commits such as fix(runtime): ... or docs: .... Each commit must be independently buildable and should contain one logical change. Pull requests should explain behavior, compatibility impact, and verification performed.

Maintainer guide

Release channels

  • main is the stable channel.
  • edge is the release candidate for upcoming changes.
  • Version tags use Semantic Versioning and the form vMAJOR.MINOR.PATCH.

The unified architecture was promoted to main as v1.0.0 on August 30, 2026.

Compatibility policy

Public flake outputs, module options, and library functions introduced in 1.x remain usable throughout 1.x. Renames and moves require:

  1. A compatibility alias with an evaluation warning.
  2. A direct replacement in the warning and migration guide.
  3. Contract coverage for the old and new names.
  4. Removal only in the next major release.

Security fixes may override this policy when preserving behavior would leave users exposed. Document the exception in the release notes.

Release process

  1. Confirm edge passes every required CI job.
  2. Review deprecation warnings and the migration guide.
  3. Build generated documentation with nix build .#docs.
  4. Merge the tested edge release into main without unrelated changes.
  5. Create an annotated version tag on the stable commit.
  6. Push the tag. The release workflow validates the commit and publishes generated release notes.
  7. Verify a fresh consumer can evaluate each supported host integration.

Do not edit generated release notes or generated option documentation in source. Fix their inputs instead.

Supported systems

CI evaluates all declared systems and builds on x86_64 Linux, ARM Linux, Intel macOS, and Apple Silicon macOS. A system is supported only when its native CI job is required and passing.

Intel macOS uses the Nixpkgs 26.05 Darwin branch, which receives security fixes through the end of 2026. Reassess its support plan before that maintenance window closes.

1. Mutable vs. Immutable State Separation

Date: 2026-08-15

Status

Accepted

Context

Pi Coding Agent manages both declarative resources (settings, packages, extensions, skills, prompt templates, themes, custom model definitions) and mutable runtime state:

  • Session history (sessions/ or PI_CODING_AGENT_SESSION_DIR)
  • Authentication credentials and tokens (auth.json)
  • Runtime lock files
  • Debug log files (pi-debug.log)

When PI_CODING_AGENT_DIR is pointed directly to a read-only path in /nix/store, Pi attempts to call writeFileSync to ensure auth.json exists on startup and fails with EACCES: permission denied.

Decision

  1. Store declarative files (settings.json, models.json, packaged extensions, skills, themes, prompts) immutably in the Nix store.
  2. In Home Manager mode, link settings.json and models.json into the user’s mutable agent directory (~/.pi/agent/ or $XDG_CONFIG_HOME/pi/agent/), leaving auth.json and sessions/ writable by Pi.
  3. In standalone and devShell wrapper mode, default mutable state to the user’s standard home directory (~/.pi/agent) while instructing the wrapper to read declarative configuration from the generated store paths, and allow configuring sessionDir / PI_CODING_AGENT_SESSION_DIR.
  4. Ensure no secret tokens or keys are written to /nix/store. Passwords and API keys remain external environment variables or are managed via auth.json / secret managers.

Consequences

  • Pi runs smoothly without permission errors.
  • Declarative settings and extensions are 100% reproducible via Nix.
  • Sessions and auth state persist normally without polluting the Nix store.

2. Adoption of Nixvim Architectural Patterns and Composability

Date: 2026-08-26

Status

Accepted

Context

As nixpi evolved into a declarative framework for configuring the Pi coding agent, it became necessary to benchmark its architecture against mature, large-scale Nix configuration frameworks. Neovim’s premier Nix framework, nixvim (with 450+ plugins, multi-platform integrations, and high composability), offers battle-tested design patterns for configuration management, module scaling, package distribution, and testing.

Key architectural gaps in early nixpi versions included:

  1. Lack of package composition: Evaluating a Pi package via makePi returned an opaque derivation. Users could not easily inspect the evaluated config/options or extend an already-configured instance (pkg.extend { ... }).
  2. Boilerplate in module definitions: Extensions and skills required repetitive option definitions (enable, package, settings, runtimePackages).
  3. Platform wrapper fragmentation: Only Home Manager was integrated, with no native NixOS or nix-darwin system module wrappers.
  4. Flake output rigidity: Flake exports were tied to specific naming conventions without standardized aliases or unified builder endpoints.

Decision

We adopt the following architectural patterns from Nixvim into nixpi:

1. Package Distribution Strategy

  • Nixpi separates declarative module abstractions from package definitions.
  • Modules accept a package option defaulting to either the internal package or an upstream package, allowing users to override the underlying derivation cleanly.
  • Direct escape hatches (programs.pi.extraPackages, programs.pi.extraExtensions, programs.pi.extraSkills) allow injecting arbitrary derivations without needing dedicated modules.

2. Standalone Package Composability (passthru.extend)

  • makePi now wraps the resulting derivation with passthru = { config, options, extend, unwrapped }.
  • Calling pkg.extend { programs.pi.skills.commitStyle.enable = true; } evaluates a new Pi package by appending the additional modules to the base configuration, mirroring Nixvim’s makeNixvim composability.

3. Standardized Module Factories (lib.mkPiExtensionModule & lib.mkPiSkillModule)

  • Introduce helper generators in lib/module-factories.nix that generate standardized module schemas:
    • programs.pi.extensions.<name>.enable
    • programs.pi.extensions.<name>.package
    • programs.pi.extensions.<name>.settings
    • programs.pi.extensions.<name>.runtimePackages
  • Reduces code duplication across extension and skill definitions by ~70%.

4. Multi-Platform Module Unification (integrations/)

  • Establish a shared evaluation engine (integrations/shared.nix) providing consistent options across:
    • Standalone: lib.makePi / legacyPackages.${system}.makePiWithModule
    • Home Manager: homeModules.default (with homeManagerModules preserved as a backwards-compatible alias)
    • NixOS: nixosModules.default and nixosModules.pi
    • Nix-Darwin: nixDarwinModules.default and nixDarwinModules.pi

5. Strict Backwards Compatibility & Graceful Deprecations

  • All existing flake outputs (piModules, homeManagerModules, packages.*, lib.*) remain 100% functional.
  • Any naming modernizations (e.g. homeModules over homeManagerModules) provide transparent compatibility layers and non-breaking warnings.

Consequences

  • Pre-configured Pi environments can be dynamically extended in devshells and downstream flakes using .extend { ... }.
  • System-level configuration is now supported natively across Linux (NixOS) and macOS (nix-darwin).
  • Authoring new extensions and skills requires significantly less boilerplate.
  • Existing user configurations and test suites continue to work without any breaking changes.