diff --git a/docs/release-notes/rl-0.8.md b/docs/release-notes/rl-0.8.md
index cf4dd169..c2e180ea 100644
--- a/docs/release-notes/rl-0.8.md
+++ b/docs/release-notes/rl-0.8.md
@@ -194,6 +194,10 @@
   [golines](https://github.com/segmentio/golines) and
   [gofumpt](https://github.com/mvdan/gofumpt).
 
+[UltraGhostie](https://github.com/UltraGhostie)
+
+- Add [harpoon](https://github.com/ThePrimeagen/harpoon) plugin for navigation
+
 [MaxMur](https://github.com/TheMaxMur):
 
 - Add YAML support under `vim.languages.yaml`.
@@ -201,16 +205,17 @@
 [alfarel](https://github.com/alfarelcynthesis):
 
 - Add missing `yazi.nvim` dependency (`snacks.nvim`).
-- Add [mkdir.nvim](https://github.com/jghauser/mkdir.nvim) plugin
-  for automatic creation of parent directories when editing a nested file.
-- Add [nix-develop.nvim](https://github.com/figsoda/nix-develop.nvim) plugin
-  for in-neovim `nix develop`, `nix shell` and more.
-- Add [direnv.vim](https://github.com/direnv/direnv.vim) plugin
-  for automatic syncing of nvim shell environment with direnv's.
+
+- Add [mkdir.nvim](https://github.com/jghauser/mkdir.nvim) plugin for automatic
+  creation of parent directories when editing a nested file.
+- Add [nix-develop.nvim](https://github.com/figsoda/nix-develop.nvim) plugin for
+  in-neovim `nix develop`, `nix shell` and more.
+- Add [direnv.vim](https://github.com/direnv/direnv.vim) plugin for automatic
+  syncing of nvim shell environment with direnv's.
 - Add [blink.cmp] source options and some default-disabled sources.
 - Add [blink.cmp] option to add
-  [friendly-snippets](https://github.com/rafamadriz/friendly-snippets)
-  so blink.cmp can source snippets from it.
+  [friendly-snippets](https://github.com/rafamadriz/friendly-snippets) so
+  blink.cmp can source snippets from it.
 
 [TheColorman](https://github.com/TheColorman):
 
diff --git a/modules/plugins/utility/default.nix b/modules/plugins/utility/default.nix
index 0f0956fb..a1574b97 100644
--- a/modules/plugins/utility/default.nix
+++ b/modules/plugins/utility/default.nix
@@ -6,6 +6,7 @@
     ./direnv
     ./fzf-lua
     ./gestures
+    ./harpoon
     ./icon-picker
     ./images
     ./leetcode-nvim
diff --git a/modules/plugins/utility/harpoon/config.nix b/modules/plugins/utility/harpoon/config.nix
new file mode 100644
index 00000000..487e67e4
--- /dev/null
+++ b/modules/plugins/utility/harpoon/config.nix
@@ -0,0 +1,41 @@
+{
+  options,
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib.modules) mkIf;
+  inherit (lib.nvim.binds) pushDownDefault mkKeymap;
+
+  cfg = config.vim.navigation.harpoon;
+
+  keys = cfg.mappings;
+  inherit (options.vim.navigation.harpoon) mappings;
+in {
+  config = mkIf cfg.enable {
+    vim = {
+      startPlugins = ["plenary-nvim"];
+
+      lazy.plugins.harpoon = {
+        package = "harpoon";
+        setupModule = "harpoon";
+        inherit (cfg) setupOpts;
+
+        cmd = ["Harpoon"];
+
+        keys = [
+          (mkKeymap "n" keys.markFile "<Cmd>lua require('harpoon'):list():add()<CR>" {desc = mappings.markFile.description;})
+          (mkKeymap "n" keys.listMarks "<Cmd>lua require('harpoon').ui:toggle_quick_menu(require('harpoon'):list())<CR>" {desc = mappings.listMarks.description;})
+          (mkKeymap "n" keys.file1 "<Cmd>lua require('harpoon'):list():select(1)<CR>" {desc = mappings.file1.description;})
+          (mkKeymap "n" keys.file2 "<Cmd>lua require('harpoon'):list():select(2)<CR>" {desc = mappings.file2.description;})
+          (mkKeymap "n" keys.file3 "<Cmd>lua require('harpoon'):list():select(3)<CR>" {desc = mappings.file3.description;})
+          (mkKeymap "n" keys.file4 "<Cmd>lua require('harpoon'):list():select(4)<CR>" {desc = mappings.file4.description;})
+        ];
+      };
+
+      binds.whichKey.register = pushDownDefault {
+        "<leader>a" = "Harpoon Mark";
+      };
+    };
+  };
+}
diff --git a/modules/plugins/utility/harpoon/default.nix b/modules/plugins/utility/harpoon/default.nix
new file mode 100644
index 00000000..21637c5b
--- /dev/null
+++ b/modules/plugins/utility/harpoon/default.nix
@@ -0,0 +1,6 @@
+{
+  imports = [
+    ./harpoon.nix
+    ./config.nix
+  ];
+}
diff --git a/modules/plugins/utility/harpoon/harpoon.nix b/modules/plugins/utility/harpoon/harpoon.nix
new file mode 100644
index 00000000..4478c938
--- /dev/null
+++ b/modules/plugins/utility/harpoon/harpoon.nix
@@ -0,0 +1,53 @@
+{lib, ...}: let
+  inherit (lib.options) mkEnableOption mkOption;
+  inherit (lib.types) bool;
+  inherit (lib.nvim.binds) mkMappingOption;
+  inherit (lib.nvim.types) mkPluginSetupOption luaInline;
+  inherit (lib.generators) mkLuaInline;
+in {
+  options.vim.navigation.harpoon = {
+    mappings = {
+      markFile = mkMappingOption "Mark file [Harpoon]" "<leader>a";
+      listMarks = mkMappingOption "List marked files [Harpoon]" "<C-e>";
+      file1 = mkMappingOption "Go to marked file 1 [Harpoon]" "<C-j>";
+      file2 = mkMappingOption "Go to marked file 2 [Harpoon]" "<C-k>";
+      file3 = mkMappingOption "Go to marked file 3 [Harpoon]" "<C-l>";
+      file4 = mkMappingOption "Go to marked file 4 [Harpoon]" "<C-;>";
+    };
+
+    enable = mkEnableOption "Quick bookmarks on keybinds [Harpoon]";
+
+    setupOpts = mkPluginSetupOption "Harpoon" {
+      defaults = {
+        save_on_toggle = mkOption {
+          type = bool;
+          default = false;
+          description = ''
+            Any time the ui menu is closed then we will save the
+            state back to the backing list, not to the fs
+          '';
+        };
+        sync_on_ui_close = mkOption {
+          type = bool;
+          default = false;
+          description = ''
+            Any time the ui menu is closed then the state of the
+            list will be sync'd back to the fs
+          '';
+        };
+        key = mkOption {
+          type = luaInline;
+          default = mkLuaInline ''
+            function()
+              return vim.loop.cwd()
+            end
+          '';
+          description = ''
+            How the out list key is looked up. This can be useful
+            when using worktrees and using git remote instead of file path
+          '';
+        };
+      };
+    };
+  };
+}
diff --git a/npins/sources.json b/npins/sources.json
index a68a1ea4..f5e12e4b 100644
--- a/npins/sources.json
+++ b/npins/sources.json
@@ -519,6 +519,18 @@
       "url": "https://github.com/ellisonleao/gruvbox.nvim/archive/089b60e92aa0a1c6fa76ff527837cd35b6f5ac81.tar.gz",
       "hash": "0mr8q2xi4s2anibll8lhxax7q1akyg687bp5r58gckkhi04064q4"
     },
+    "harpoon": {
+      "type": "Git",
+      "repository": {
+        "type": "GitHub",
+        "owner": "ThePrimeagen",
+        "repo": "harpoon"
+      },
+      "branch": "harpoon2",
+      "revision": "ed1f853847ffd04b2b61c314865665e1dadf22c7",
+      "url": "https://github.com/ThePrimeagen/harpoon/archive/ed1f853847ffd04b2b61c314865665e1dadf22c7.tar.gz",
+      "hash": "1dcpdlna2lff9dlsh6i4v16qmn5r9279wdvn0ry3xg4abqwnzc9g"
+    },
     "haskell-tools-nvim": {
       "type": "Git",
       "repository": {