Archived. pi ships its own flake (
github:earendil-works/pi); build it from there. The extensions and durapi moved to their own repositories: pi-rlm, pi-chronobreak, pi-recap (a fork of L2ncE/pi-recap), pi-donsetch and durapi. Load extensions by adding their store paths topackagesin pi'ssettings.json. prime-agent, prime-bun, pi-fusion and the omp wrapper were dropped; their last versions are in this repository's history.
Nix flake for building pi and its forks (prime-agent, prime-bun) with optional extension bundles.
Features:
- Base
pipackage built from source with upstream patches prime-agentandprime-bunvariants built from their own sources- Pre-configured extension packages with lifecycle stages (active/testing/paused/retired)
pi-full: base pi with all active extensions bundleddurapi: a durable coding agent on pi-durable, forked from pi's experimental demo (durapi/README.md)- Builder functions for custom extension combinations
- Flag-driven extension selection for downstream flakes
- Bundled extensions load automatically via
PI_DEFAULT_PACKAGES— nosettings.jsonedits
nix profile install github:y0usaf/pi-flake#pi
# OR in your flake:
# inputs.pi-flake.packages.x86_64-linux.pinix profile install github:y0usaf/pi-flake#pi-full
# OR in your flake:
# inputs.pi-flake.packages.x86_64-linux.pi-fullnix profile install github:y0usaf/pi-flake#prime-agent
nix profile install github:y0usaf/pi-flake#prime-bun # Bun-compiled standalone binary{
inputs.pi-flake.url = "github:y0usaf/pi-flake";
inputs.nixpkgs.follows = "pi-flake/nixpkgs";
outputs = { self, pi-flake, nixpkgs }: let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
packages.x86_64-linux.my-pi = pi-flake.lib.piWithExtensions {
inherit pkgs;
pi = pi-flake.packages.${system}.pi;
extensions = {
webfetch = pi-flake.packages.${system}."pi-webfetch";
"gecko-websearch" = pi-flake.packages.${system}."pi-gecko-websearch";
};
};
};
}Flake inputs cannot pass arbitrary booleans into another flake's outputs.
Use a flag attrset in your consuming flake:
{
inputs.pi-flake.url = "github:y0usaf/pi-flake";
inputs.nixpkgs.follows = "pi-flake/nixpkgs";
outputs = { self, pi-flake, nixpkgs }: let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
packages.${system}.my-pi = pi-flake.lib.piWithExtensionFlags {
inherit pkgs;
extensionFlags = {
aliases = true;
chronobreak = true;
webfetch = true;
"gecko-websearch" = false;
sentinel = true;
recap = true;
};
};
};
}Only flags set to true are bundled. Unknown flags fail the build with an
assertion.
{
inputs.pi-flake.url = "github:y0usaf/pi-flake";
inputs.pi-flake.inputs.nixpkgs.follows = "nixpkgs";
outputs = { nixpkgs, pi-flake, ... }: {
nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
pi-flake.nixosModules.default
{
programs.pi = {
enable = true;
# Option 1: all active extensions, same contents as .#pi-full
full = true;
# Option 2: selected extensions
# extensions = {
# webfetch = true;
# };
# Option 3: concrete package
# package = pi-flake.packages.x86_64-linux.pi-full;
};
}
];
};
};
}The module installs config.programs.pi.finalPackage into
environment.systemPackages and sets PI_SKIP_VERSION_CHECK=1 and
PI_TELEMETRY=0. Bundled extensions load through the installed wrapper; no
settings.json entries or extra Nix config are needed.
Active extensions (shipped in pi-full):
| Name | Description |
|---|---|
pi-aliases |
Configurable bash command aliases — defaults: grep→rg, find→fd |
pi-chronobreak |
Terminates assistant generation loops: detects repeated output in a turn, aborts, scrubs context, re-runs with a decisive-action directive |
pi-webfetch |
Fetch a URL and return its content as markdown |
pi-gecko-websearch |
Web search and browsing via headless Gecko browser (Marionette) |
pi-sentinel |
Detects abrupt run endings via a sparse context-free judge, continues the run when the stop was a cutoff |
pi-recap |
Claude Code-style session recap: one-line recap above the status bar |
pi-rlm |
Recursive sub-calls and child agents for codemode scripts, with a /rlm children view |
pi-yourshell |
Runs the bash tool through your own $SHELL instead of pi's hardcoded bash |
extensions/registry.nix assigns every bundled extension a lifecycle stage:
| Stage | Effect |
|---|---|
active |
In the default bundle (pi-full) and built by nix flake check |
testing |
Built and checked, but excluded from the default bundle; opt-in via programs.pi.extensions.<name> (NixOS module emits a warning) |
paused |
Source kept in the tree, but not built, bundled, or checked |
retired |
Removed from the tree; git history is the archive. Not built or bundled |
Promote/demote an extension by editing its stage in
extensions/registry.nix; packages, checks, the default bundle, and the NixOS
module all follow from that single declaration.
Bundled extensions are copied into $out/share/pi/extensions/<name>/. The
wrapper exposes $out/share/pi through PI_DEFAULT_PACKAGES, and the patched
Pi package manager treats that path as a temporary/default package source at
runtime.
When you run the wrapped pi:
- The wrapper prepends its bundled package root to
PI_DEFAULT_PACKAGES. - Pi resolves resources from that package root using the same package/convention discovery as normal package sources.
- The extensions load for that process only.
- User/project
settings.jsonfiles are not created or modified.
--no-extensions still disables these bundled defaults because they enter
through the normal package resolution path, not as CLI-forced extension paths.
If you want full control:
-
Build base pi:
nix build .#pi -
Build your chosen extensions:
nix build .#pi-webfetch -
Add to
~/.pi/agent/settings.json:{ "packages": [ "/path/to/result-pi-webfetch" ] }
pi- Base pi, no extensionspi-full- pi with all active extensions bundledprime-agent- Prime Intellect fork, node bundle with vendored runtime node_modulesprime-bun- Bun-compiled standalone binary, parallel to prime-agentdurapi- Durable coding agent on pi-durable, run from pi's TypeScript sourcedurapi-full- durapi with its extensions
inputs.pi-flake.packages.<system>."pi-aliases"
inputs.pi-flake.packages.<system>."pi-chronobreak"
inputs.pi-flake.packages.<system>."pi-webfetch"
inputs.pi-flake.packages.<system>."pi-gecko-websearch"
inputs.pi-flake.packages.<system>."pi-sentinel"
inputs.pi-flake.packages.<system>."pi-recap"
inputs.pi-flake.packages.<system>."pi-yourshell"pi-flake.nixosModules.default- NixOS module exposingprograms.pi.*pi-flake.lib.piWithExtensions { pkgs; pi; extensions; }- bundle an explicit extension attrsetpi-flake.lib.piWithExtensionFlags { pkgs; extensionFlags; }- bundle extensions whose flags aretruepi-flake.lib.extensionPackagesFor system- available extension attrset keyed by bundled namepi-flake.lib.defaultExtensionPackagesFor system- active-stage extensions only (whatpi-fulluses)pi-flake.lib.enabledExtensions { system; extensionFlags; }- resolve flags to extension packagespi-flake.lib.extensionRegistry- the lifecycle registry
# Build base pi
nix build .#pi
# Build an extension
nix build .#pi-webfetch
# Build full bundle
nix build .#pi-full
# Build fork variants
nix build .#prime-agent
nix build .#prime-bun
# Enter dev shell
nix develop
# Run Biome linting
nix develop -c biome lint .
# Run the Biome flake check only (replace the system if needed)
nix build .#checks.x86_64-linux.biome-lintnix/model-data is the vendored packages/ai/src/providers/data for the
pinned piSrc: the whole catalog content, while the generated shards are
flat imports of it. New models therefore land without a piSrc bump.
# hydrate from models.dev and install into nix/model-data
nix run .#refresh-model-data
# or into another directory, or from another checkout's generator
nix run .#refresh-model-data -- /tmp/model-data
nix/refresh-model-data.sh /path/to/pi-src /tmp/model-dataThe app copies the pinned checkout to a temp tree, runs upstream's
generate-models.ts --strict --data-only (network: models.dev plus the
OpenRouter, NVIDIA, Vercel AI Gateway and Radius public catalogs), validates
with check:model-data, prints the model ids added or removed per shard, and
installs the result. Shards are single-line JSON, so read the printed delta
instead of the raw diff. Data newer than the snapshot still reaches a running
pi through the pi.dev catalog overlay (pi update --models).
Patches are a last resort: anything reachable through an env var or user
config is done that way instead, because context diffs rot on every piSrc
bump.
Current patch set applied to upstream pi:
default-package-sources-env.patch- Adds non-persistentPI_DEFAULT_PACKAGESpackage sources for Nix-bundled resources
Removed patches and their replacements:
- model regeneration: the build runs upstream's root
build:offline, which validates the vendorednix/model-data(check:model-data) instead of fetching, then the bun compile and asset copy frombuild:binary. - user-message bar: dropped as cosmetic.
"userMessageBg": ""in a theme puts user messages on the terminal background instead of a box. - TUI overlay invalidate guard: dropped. It came in while pi-interview was
bundled; no bundled extension shows overlays now, and upstream's
Componentinterface requiresinvalidate(). - install telemetry:
PI_TELEMETRY=0exported by both wrappers and by the NixOS module.isInstallTelemetryEnabledprefers the env var over settings, and gates bothreportInstallTelemetryand the provider attribution headers inprovider-attribution.ts(the old patch only covered the former). - tree-filter backward cycle: unbind it in
~/.pi/agent/keybindings.json(getAgentDir=$HOME/.pi/agent) with{ "app.tree.filter.cycleBackward": [] }— an empty key list never matches.
- Dependabot can update lock files, but upstream
piSrcbumps may require manualnpmDepsHashand/or patch refreshes inflake.nix.