{"id":37042876,"url":"https://github.com/Enigama/remarks.nvim","last_synced_at":"2026-01-21T06:01:05.752Z","repository":{"id":331098702,"uuid":"1124831309","full_name":"Enigama/remarks.nvim","owner":"Enigama","description":"Neovim plugin for git-remarks","archived":false,"fork":false,"pushed_at":"2026-01-12T12:53:32.000Z","size":28,"stargazers_count":7,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-12T19:46:48.233Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Enigama.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-29T17:31:43.000Z","updated_at":"2026-01-12T12:41:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Enigama/remarks.nvim","commit_stats":null,"previous_names":["enigama/remarks.nvim"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Enigama/remarks.nvim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Enigama%2Fremarks.nvim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Enigama%2Fremarks.nvim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Enigama%2Fremarks.nvim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Enigama%2Fremarks.nvim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Enigama","download_url":"https://codeload.github.com/Enigama/remarks.nvim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Enigama%2Fremarks.nvim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28628700,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T05:00:26.175Z","updated_at":"2026-01-21T06:01:05.720Z","avatar_url":"https://github.com/Enigama.png","language":"Lua","readme":"# remarks.nvim\n\nNeovim plugin for [git-remarks](https://github.com/Enigama/git-remarks) — personal developer notes attached to Git commits.\n\n## Features\n\n- **Bring your own picker** — Use telescope, fzf-lua, mini.pick, snacks.nvim, or any picker you prefer\n- **Quick add** — Add remarks via input prompt\n- **Full add** — Add remarks with YAML template in a buffer\n- **Visual selection context** — Automatically add file context from visual selection when editing remarks\n- **Configurable** — Float, split, vsplit, or tab for edit buffers\n- **Zero dependencies** — Falls back to `vim.ui.select()` when no picker is configured\n\n## Requirements\n\n- Neovim 0.9+\n- [git-remarks](https://github.com/Enigama/git-remarks) CLI installed and in PATH\n\n## Installation\nBefore install the plugin make sure that you have installed [git-remarks](https://github.com/Enigama/git-remarks)\n\n### lazy.nvim\n\n```lua\n{\n  \"Enigama/remarks.nvim\",\n  config = function()\n    require(\"remarks\").setup()\n  end,\n}\n```\n\n### packer.nvim\n\n```lua\nuse {\n  \"Enigama/remarks.nvim\",\n  config = function()\n    require(\"remarks\").setup()\n  end,\n}\n```\n\n## Configuration\n\n```lua\nrequire(\"remarks\").setup({\n  edit = {\n    style = \"float\",    -- \"float\" | \"split\" | \"vsplit\" | \"tab\"\n    width = 0.6,        -- float width (0-1 = percentage)\n    height = 0.4,       -- float height\n  },\n  default_type = \"thought\", -- default remark type\n  picker = nil, -- function(remarks, opts) | nil for vim.ui.select fallback\n})\n```\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `:Remarks` | Open picker with all active remarks |\n| `:RemarksAdd [type]` | Quick add a remark (thought, doubt, todo, decision) |\n| `:RemarksAddFull` | Add a remark via buffer with full template |\n| `:RemarksShow` | Show remarks on current commit |\n| `:RemarksInit` | Initialize git-remarks hooks in repository |\n\n## Picker Configuration\n\nBy default, remarks.nvim uses `vim.ui.select()` which works out of the box and can be enhanced with [dressing.nvim](https://github.com/stevearc/dressing.nvim).\n\nTo use a custom picker, provide a function that receives:\n- `remarks` — List of remark objects with fields: `id`, `type`, `age`, `sha`, `is_head`, `body`\n- `opts` — Options table (e.g., `{ commit = \"HEAD\" }` when filtering by commit)\n\n### Recommended Keybindings\n\n| Key | Action |\n|-----|--------|\n| `\u003cCR\u003e` | Edit selected remark |\n| `\u003cC-e\u003e` | Edit remark with visual selection context |\n| `d` / `x` / `\u003cC-d\u003e` | Resolve (delete) selected remark |\n| `a` / `\u003cC-a\u003e` | Add new remark |\n| `\u003cC-t\u003e` | Edit selected remark in new tab |\n\n### Telescope\n\n```lua\n{\n  \"Enigama/remarks.nvim\",\n  dependencies = { \"nvim-telescope/telescope.nvim\" },\n  config = function()\n    local pickers = require(\"telescope.pickers\")\n    local finders = require(\"telescope.finders\")\n    local conf = require(\"telescope.config\").values\n    local actions = require(\"telescope.actions\")\n    local action_state = require(\"telescope.actions.state\")\n    local previewers = require(\"telescope.previewers\")\n\n    local function telescope_picker(remarks, opts)\n      pickers.new({}, {\n        prompt_title = \"Remarks\",\n        finder = finders.new_table({\n          results = remarks,\n          entry_maker = function(remark)\n            -- Extract first line of body as preview\n            local preview = remark.body:match(\"^[^\\r\\n]+\") or \"\"\n            if #preview \u003e 50 then\n              preview = preview:sub(1, 47) .. \"...\"\n            end\n\n            local display = string.format(\n              \"[%s] %s: %s%s\",\n              remark.id,\n              remark.type,\n              preview,\n              remark.is_head and \" (HEAD)\" or \"\"\n            )\n            return {\n              value = remark,\n              display = display,\n              ordinal = display,\n            }\n          end,\n        }),\n        sorter = conf.generic_sorter({}),\n        previewer = previewers.new_buffer_previewer({\n          title = \"Remark\",\n          define_preview = function(self, entry)\n            local remark = entry.value\n            local lines = {\n              \"id: \" .. remark.id,\n              \"type: \" .. remark.type,\n              \"commit: \" .. remark.sha,\n              \"age: \" .. remark.age,\n              \"\",\n              \"---\",\n              \"\",\n            }\n            for line in remark.body:gmatch(\"[^\\r\\n]+\") do\n              table.insert(lines, line)\n            end\n            vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)\n            vim.bo[self.state.bufnr].filetype = \"yaml\"\n          end,\n        }),\n        attach_mappings = function(prompt_bufnr, map)\n          -- \u003cCR\u003e - Edit selected remark\n          actions.select_default:replace(function()\n            local selection = action_state.get_selected_entry()\n            actions.close(prompt_bufnr)\n            if selection then\n              require(\"remarks.buffer\").edit_remark(selection.value)\n            end\n          end)\n\n          -- d / x - Resolve (delete) selected remark\n          local resolve_action = function()\n            local selection = action_state.get_selected_entry()\n            if selection then\n              local remark = selection.value\n              vim.ui.select({ \"Yes\", \"No\" }, {\n                prompt = \"Resolve remark [\" .. remark.id .. \"]?\",\n              }, function(choice)\n                if choice == \"Yes\" then\n                  local result = require(\"remarks.git\").resolve(remark.id)\n                  if result.success then\n                    vim.notify(\"Resolved [\" .. remark.id .. \"]\", vim.log.levels.INFO)\n                    actions.close(prompt_bufnr)\n                    vim.schedule(function()\n                      require(\"remarks.picker\").pick_remarks(opts)\n                    end)\n                  else\n                    vim.notify(\"Failed to resolve: \" .. (result.error or \"unknown\"), vim.log.levels.ERROR)\n                  end\n                end\n              end)\n            end\n          end\n\n          map(\"i\", \"\u003cC-d\u003e\", resolve_action)\n          map(\"n\", \"d\", resolve_action)\n          map(\"n\", \"x\", resolve_action)\n\n          -- a - Add new remark\n          local add_action = function()\n            actions.close(prompt_bufnr)\n            require(\"remarks.buffer\").quick_add()\n          end\n\n          map(\"i\", \"\u003cC-a\u003e\", add_action)\n          map(\"n\", \"a\", add_action)\n\n          -- \u003cC-t\u003e - Edit in new tab\n          local edit_in_tab = function()\n            local selection = action_state.get_selected_entry()\n            actions.close(prompt_bufnr)\n            if selection then\n              require(\"remarks.buffer\").edit_remark(selection.value, { style = \"tab\" })\n            end\n          end\n\n          map(\"i\", \"\u003cC-t\u003e\", edit_in_tab)\n          map(\"n\", \"\u003cC-t\u003e\", edit_in_tab)\n\n          -- \u003cC-e\u003e - Edit with visual selection context\n          local edit_with_context = function()\n            local selection = action_state.get_selected_entry()\n            actions.close(prompt_bufnr)\n            if selection then\n              require(\"remarks.buffer\").edit_remark(selection.value, { include_visual_context = true })\n            end\n          end\n\n          map(\"i\", \"\u003cC-e\u003e\", edit_with_context)\n          map(\"n\", \"\u003cC-e\u003e\", edit_with_context)\n\n          return true\n        end,\n      }):find()\n    end\n\n    require(\"remarks\").setup({\n      picker = telescope_picker,\n    })\n  end,\n}\n```\n\n### fzf-lua\n\n```lua\n{\n  \"Enigama/remarks.nvim\",\n  dependencies = { \"ibhagwan/fzf-lua\" },\n  config = function()\n    local function fzf_picker(remarks, opts)\n      local fzf = require(\"fzf-lua\")\n      local builtin = require(\"fzf-lua.previewer.builtin\")\n\n      local entries = {}\n      local remark_map = {}\n      for _, remark in ipairs(remarks) do\n        local display = string.format(\n          \"[%s] %s · %s · %s%s\",\n          remark.id,\n          remark.type,\n          remark.age,\n          remark.sha,\n          remark.is_head and \" (HEAD)\" or \"\"\n        )\n        table.insert(entries, display)\n        remark_map[display] = remark\n      end\n\n      -- Custom previewer using fzf-lua's builtin base\n      local RemarksPreviewer = builtin.base:extend()\n\n      function RemarksPreviewer:new(o, fzf_opts, fzf_win)\n        RemarksPreviewer.super.new(self, o, fzf_opts, fzf_win)\n        setmetatable(self, RemarksPreviewer)\n        return self\n      end\n\n      function RemarksPreviewer:populate_preview_buf(entry_str)\n        local remark = remark_map[entry_str]\n        if not remark then\n          return\n        end\n\n        local lines = {\n          \"id: \" .. remark.id,\n          \"type: \" .. remark.type,\n          \"commit: \" .. remark.sha,\n          \"age: \" .. remark.age,\n          \"\",\n          \"---\",\n          \"\",\n        }\n        for line in remark.body:gmatch(\"[^\\r\\n]+\") do\n          table.insert(lines, line)\n        end\n\n        local bufnr = self:get_tmp_buffer()\n        vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)\n        vim.bo[bufnr].filetype = \"yaml\"\n        self:set_preview_buf(bufnr)\n        if self.win and self.win.update_scrollbar then\n          self.win:update_scrollbar()\n        end\n      end\n\n      fzf.fzf_exec(entries, {\n        prompt = \"Remarks\u003e \",\n        previewer = RemarksPreviewer,\n        actions = {\n          [\"default\"] = function(selected)\n            if selected[1] then\n              local remark = remark_map[selected[1]]\n              require(\"remarks.buffer\").edit_remark(remark)\n            end\n          end,\n          [\"ctrl-d\"] = function(selected)\n            if selected[1] then\n              local remark = remark_map[selected[1]]\n              local result = require(\"remarks.git\").resolve(remark.id)\n              if result.success then\n                vim.notify(\"Resolved [\" .. remark.id .. \"]\", vim.log.levels.INFO)\n                vim.schedule(function()\n                  require(\"remarks.picker\").pick_remarks(opts)\n                end)\n              end\n            end\n          end,\n          [\"ctrl-e\"] = function(selected)\n            if selected[1] then\n              local remark = remark_map[selected[1]]\n              require(\"remarks.buffer\").edit_remark(remark, { include_visual_context = true })\n            end\n          end,\n        },\n      })\n    end\n\n    require(\"remarks\").setup({\n      picker = fzf_picker,\n    })\n  end,\n}\n```\n\n### mini.pick\n\n```lua\n{\n  \"Enigama/remarks.nvim\",\n  dependencies = { \"echasnovski/mini.pick\" },\n  config = function()\n    local function mini_picker(remarks, opts)\n      local MiniPick = require(\"mini.pick\")\n\n      local items = vim.tbl_map(function(remark)\n        return {\n          text = string.format(\n            \"[%s] %s · %s · %s%s\",\n            remark.id,\n            remark.type,\n            remark.age,\n            remark.sha,\n            remark.is_head and \" (HEAD)\" or \"\"\n          ),\n          remark = remark,\n        }\n      end, remarks)\n\n      MiniPick.start({\n        source = {\n          items = items,\n          name = \"Remarks\",\n          choose = function(item)\n            if item then\n              vim.schedule(function()\n                require(\"remarks.buffer\").edit_remark(item.remark)\n              end)\n            end\n          end,\n        },\n        mappings = {\n          edit_context = {\n            char = \"\u003cC-e\u003e\",\n            func = function()\n              local item = MiniPick.get_picker_matches().current\n              if item then\n                MiniPick.stop()\n                vim.schedule(function()\n                  require(\"remarks.buffer\").edit_remark(item.remark, { include_visual_context = true })\n                end)\n              end\n            end,\n          },\n        },\n      })\n    end\n\n    require(\"remarks\").setup({\n      picker = mini_picker,\n    })\n  end,\n}\n```\n\n### snacks.nvim\n\n```lua\n{\n  \"Enigama/remarks.nvim\",\n  dependencies = { \"folke/snacks.nvim\" },\n  config = function()\n    local function snacks_picker(remarks, opts)\n      local items = vim.tbl_map(function(remark)\n        return {\n          text = string.format(\n            \"[%s] %s · %s · %s%s\",\n            remark.id,\n            remark.type,\n            remark.age,\n            remark.sha,\n            remark.is_head and \" (HEAD)\" or \"\"\n          ),\n          remark = remark,\n        }\n      end, remarks)\n\n      require(\"snacks\").picker({\n        items = items,\n        title = \"Remarks\",\n        format = function(item)\n          return { { item.text } }\n        end,\n        preview = function(ctx)\n          local remark = ctx.item.remark\n          local lines = {\n            \"id: \" .. remark.id,\n            \"type: \" .. remark.type,\n            \"commit: \" .. remark.sha,\n            \"age: \" .. remark.age,\n            \"\",\n            \"---\",\n            \"\",\n          }\n          for line in remark.body:gmatch(\"[^\\r\\n]+\") do\n            table.insert(lines, line)\n          end\n          vim.bo[ctx.buf].modifiable = true\n          vim.api.nvim_buf_set_lines(ctx.buf, 0, -1, false, lines)\n          vim.bo[ctx.buf].filetype = \"yaml\"\n        end,\n        confirm = function(picker, item)\n          picker:close()\n          if item then\n            require(\"remarks.buffer\").edit_remark(item.remark)\n          end\n        end,\n        actions = {\n          edit_context = function(picker)\n            local item = picker:current()\n            picker:close()\n            if item then\n              require(\"remarks.buffer\").edit_remark(item.remark, { include_visual_context = true })\n            end\n          end,\n        },\n        win = {\n          input = {\n            keys = {\n              [\"\u003cC-e\u003e\"] = { \"edit_context\", mode = { \"i\", \"n\" } },\n            },\n          },\n        },\n      })\n    end\n\n    require(\"remarks\").setup({\n      picker = snacks_picker,\n    })\n  end,\n}\n```\n\n## Example Workflow\n\n```vim\n\" Initialize hooks in your repo (once)\n:RemarksInit\n\n\" Quick add a thought\n:RemarksAdd\n\u003e Remark (thought): Not sure about this approach\n\n\" Add with specific type\n:RemarksAdd todo\n\u003e Remark (todo): Refactor before merge\n\n\" Full add with template\n:RemarksAddFull\n\" Opens buffer:\n\" # New remark on abc1234 (feature/auth)\n\" type: thought\n\" ---\n\" Your detailed note here...\n\n\" Browse all remarks\n:Remarks\n\n\" Show remarks on current commit\n:RemarksShow\n\n\" Edit remark with visual selection context\n\" 1. Make a visual selection in your file (e.g., lines 25-35)\n\" 2. Open :Remarks picker\n\" 3. Press \u003cC-e\u003e on a remark\n\" 4. File context (file: path/to/file.ts:25-35) is automatically added\n\" 5. Start typing your comment immediately (already in insert mode)\n```\n\n## License\n\nMIT\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n","funding_links":[],"categories":["Git"],"sub_categories":["Quickfix"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEnigama%2Fremarks.nvim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEnigama%2Fremarks.nvim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEnigama%2Fremarks.nvim/lists"}