{ config, pkgs, lib, ... }: let
  # The node-gyp should be backed by the same version of nodejs as pi,
  # thus we use pkgspi.
  pkgspi = import (
    pkgs.flake-compat {src = pkgs.npinsed.ai.pi.llm-agents;}
  ).outputs.inputs.nixpkgs {};
in {
  home.file.".pi/agent/extensions/pi-hermes-memory" = {
    source = pkgspi.buildNpmPackage {
      name = "pi-hermes-memory";
      src = pkgs.npinsed.ai.pi.pi-hermes-memory;
      # npm lockfile v3 delegates to shrinkwrap → missing integrity; v2 fetcher handles this.
      npmDepsFetcherVersion = 2;
      npmDepsHash = "sha256-OeR+8j7Ayyx1jUSt6uBhQ7YsWGLR7POEnW+bLPu7UDQ=";
      patches = [ ./pi-hermes-memory-lock-integrity.patch ];
      dontNpmBuild = true;
      nativeBuildInputs = with pkgspi; [
        node-gyp
        python3
      ];
    } + /lib/node_modules/pi-hermes-memory;
  };
  home.file.".pi/agent/projects-memory".source = config.lib.file.mkOutOfStoreSymlink ~/Gist/Data/pi/projects-memory;

  # pi-hermes-memory writes MEMORY.md/USER.md via temp-file + rename, which would
  # replace per-file symlinks. Symlink the whole writable directory instead.
  home.file.".pi/agent/pi-hermes-memory".source = config.lib.file.mkOutOfStoreSymlink ~/Gist/Data/pi/pi-hermes-memory;
  my.syncthing.Gist-stignore = lib.mkAfter [
    "/Data/pi/pi-hermes-memory/sessions.db"
    "/Data/pi/pi-hermes-memory/sessions.db-*"
  ];
}