diff --git a/lua/cosmic/lsp/mappings.lua b/lua/cosmic/lsp/mappings.lua
index cd35cf5..7d96d99 100644
--- a/lua/cosmic/lsp/mappings.lua
+++ b/lua/cosmic/lsp/mappings.lua
@@ -12,7 +12,7 @@ function M.init(client, bufnr)
   buf_map('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<cr>', { desc = 'Go to declaration' })
   buf_map('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<cr>', { desc = 'Go to implementation' })
   buf_map('n', 'gt', '<cmd>lua vim.lsp.buf.type_definition()<cr>', { desc = 'Go to type definition' })
-  buf_map('n', 'gr', '<cmd>lua vim.lsp.buf.references()<cr>', { desc = 'Find references' })
+  buf_map('n', 'gr', '<cmd>lua vim.lsp.buf.references()<cr>', { desc = 'Go to reference' })
 
   -- diagnostics
   buf_map('n', '[g', '<cmd>lua vim.diagnostic.goto_prev()<cr>', { desc = 'Next diagnostic' })
diff --git a/lua/cosmic/plugins/auto-session/mappings.lua b/lua/cosmic/plugins/auto-session/mappings.lua
index acdc527..339df10 100644
--- a/lua/cosmic/plugins/auto-session/mappings.lua
+++ b/lua/cosmic/plugins/auto-session/mappings.lua
@@ -1,10 +1,11 @@
 local map = require('cosmic.utils').map
 
 -- session
-map('n', '<leader>sl', '<cmd>silent RestoreSession<cr>')
-map('n', '<leader>ss', '<cmd>SaveSession<cr>')
+map('n', '<leader>sl', '<cmd>silent RestoreSession<cr>', { desc = 'Restore session' })
+map('n', '<leader>ss', '<cmd>SaveSession<cr>', { desc = 'Save session' })
 map(
   'n',
   '<leader>si',
-  '<cmd>lua require("cosmic.utils.logger"):log("Session name: " .. require("auto-session-library").current_session_name())<cr>'
+  '<cmd>lua require("cosmic.utils.logger"):log("Session name: " .. require("auto-session-library").current_session_name())<cr>',
+  { desc = 'Print session' }
 )
diff --git a/lua/cosmic/plugins/gitsigns/init.lua b/lua/cosmic/plugins/gitsigns/init.lua
index 2fe2535..3c1a1b6 100644
--- a/lua/cosmic/plugins/gitsigns/init.lua
+++ b/lua/cosmic/plugins/gitsigns/init.lua
@@ -14,51 +14,9 @@ return {
         topdelete = { hl = 'GitSignsDelete', text = '‾', numhl = 'GitSignsDeleteNr', linehl = 'GitSignsDeleteLn' },
         changedelete = { hl = 'GitSignsChange', text = '~', numhl = 'GitSignsChangeNr', linehl = 'GitSignsChangeLn' },
       },
-      signcolumn = true, -- Toggle with `:Gitsigns toggle_signs`
-      numhl = false, -- Toggle with `:Gitsigns toggle_numhl`
-      linehl = false, -- Toggle with `:Gitsigns toggle_linehl`
-      word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff`
-      keymaps = {
-        -- Default keymap options
-        noremap = true,
-
-        ['n ]c'] = { expr = true, "&diff ? ']c' : '<cmd>Gitsigns next_hunk<CR>'" },
-        ['n [c'] = { expr = true, "&diff ? '[c' : '<cmd>Gitsigns prev_hunk<CR>'" },
-
-        ['n <leader>hs'] = '<cmd>Gitsigns stage_hunk<CR>',
-        ['v <leader>hs'] = ':Gitsigns stage_hunk<CR>',
-        ['n <leader>hu'] = '<cmd>Gitsigns undo_stage_hunk<CR>',
-        ['n <leader>hr'] = '<cmd>Gitsigns reset_hunk<CR>',
-        ['v <leader>hr'] = ':Gitsigns reset_hunk<CR>',
-        ['n <leader>hR'] = '<cmd>Gitsigns reset_buffer<CR>',
-        ['n <leader>hp'] = '<cmd>Gitsigns preview_hunk<CR>',
-        ['n <leader>hb'] = '<cmd>lua require"gitsigns".blame_line{full=true}<CR>',
-        ['n <leader>hS'] = '<cmd>Gitsigns stage_buffer<CR>',
-        ['n <leader>hU'] = '<cmd>Gitsigns reset_buffer_index<CR>',
-
-        -- Text objects
-        ['o ih'] = ':<C-U>Gitsigns select_hunk<CR>',
-        ['x ih'] = ':<C-U>Gitsigns select_hunk<CR>',
-      },
-      watch_gitdir = {
-        interval = 1000,
-        follow_files = true,
-      },
-      attach_to_untracked = true,
-      current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame`
-      current_line_blame_opts = {
-        virt_text = true,
-        virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align'
-        delay = 1000,
-        ignore_whitespace = false,
-      },
       current_line_blame_formatter_opts = {
         relative_time = false,
       },
-      sign_priority = 6,
-      update_debounce = 100,
-      status_formatter = nil, -- Use default
-      max_file_length = 40000,
       preview_config = {
         -- Options passed to nvim_open_win
         border = user_config.border,
@@ -70,6 +28,59 @@ return {
       yadm = {
         enable = false,
       },
+      on_attach = function(bufnr)
+        local gs = package.loaded.gitsigns
+        local map = u.create_buf_map(bufnr)
+        -- Navigation
+        map('n', ']c', function()
+          if vim.wo.diff then
+            return ']c'
+          end
+          vim.schedule(function()
+            gs.next_hunk()
+          end)
+          return '<Ignore>'
+        end, {
+          expr = true,
+          desc = 'Next git hunk',
+        })
+
+        map('n', '[c', function()
+          if vim.wo.diff then
+            return '[c'
+          end
+          vim.schedule(function()
+            gs.prev_hunk()
+          end)
+          return '<Ignore>'
+        end, {
+          expr = true,
+          desc = 'Prev git hunk',
+        })
+
+        -- Actions
+        map({ 'n', 'v' }, '<leader>hs', ':Gitsigns stage_hunk<CR>', { desc = 'Stage hunk' })
+        map({ 'n', 'v' }, '<leader>hr', ':Gitsigns reset_hunk<CR>', { desc = 'Reset hunk' })
+        map('n', '<leader>hS', gs.stage_buffer, { desc = 'Stage buffer' })
+        map('n', '<leader>hu', gs.undo_stage_hunk, { desc = 'Under stage hunk' })
+        map('n', '<leader>hR', gs.reset_buffer, { desc = 'Reset buffer' })
+        map('n', '<leader>hp', gs.preview_hunk, { desc = 'Preview hunk' })
+        map('n', '<leader>hb', function()
+          gs.blame_line({ full = true })
+        end, {
+          desc = 'Blame line preview',
+        })
+        map('n', '<leader>hd', gs.diffthis, { desc = '' })
+        map('n', '<leader>hD', function()
+          gs.diffthis('~')
+        end, { desc = '' })
+
+        map('n', '<leader>htb', gs.toggle_current_line_blame, { desc = 'Toggle blame (virtual text)' })
+        map('n', '<leader>htd', gs.toggle_deleted, { desc = 'Toggle deleted' })
+
+        -- Text object
+        map({ 'o', 'x' }, 'ih', ':<C-U>Gitsigns select_hunk<CR>', { desc = 'Select hunk' })
+      end,
     }, user_config.plugins.gitsigns or {}))
   end,
   enabled = not vim.tbl_contains(user_config.disable_builtin_plugins, 'gitsigns'),
diff --git a/lua/cosmic/plugins/nvim-tree/mappings.lua b/lua/cosmic/plugins/nvim-tree/mappings.lua
index 71fb810..a598e62 100644
--- a/lua/cosmic/plugins/nvim-tree/mappings.lua
+++ b/lua/cosmic/plugins/nvim-tree/mappings.lua
@@ -1,4 +1,4 @@
 local map = require('cosmic.utils').map
 
-map('n', '<C-n>', ':NvimTreeToggle<CR>')
-map('n', '<leader>r', ':NvimTreeRefresh<CR>')
+map('n', '<C-n>', ':NvimTreeToggle<CR>', { desc = 'Toggle Tree' })
+map('n', '<leader>r', ':NvimTreeRefresh<CR>', { desc = 'Refresh Tree' })
diff --git a/lua/cosmic/plugins/telescope/mappings.lua b/lua/cosmic/plugins/telescope/mappings.lua
index 4516bb7..f93af64 100644
--- a/lua/cosmic/plugins/telescope/mappings.lua
+++ b/lua/cosmic/plugins/telescope/mappings.lua
@@ -11,15 +11,20 @@ end
 
 M.init = function()
   -- navigation
-  map('n', '<leader>ff', '<cmd>lua require("cosmic.plugins.telescope.mappings").project_files()<cr>')
-  map('n', '<leader>fp', ':Telescope find_files<cr>')
-  map('n', '<leader>fk', ':Telescope buffers<cr>')
-  map('n', '<leader>fs', ':Telescope live_grep<cr>')
-  map('n', '<leader>fw', ':Telescope grep_string<cr>')
+  map(
+    'n',
+    '<leader>ff',
+    '<cmd>lua require("cosmic.plugins.telescope.mappings").project_files()<cr>',
+    { desc = 'Find git files' }
+  )
+  map('n', '<leader>fp', ':Telescope find_files<cr>', { desc = 'Find file' })
+  map('n', '<leader>fk', ':Telescope buffers<cr>', { desc = 'Find buffer' })
+  map('n', '<leader>fs', ':Telescope live_grep<cr>', { desc = 'Live grep' })
+  map('n', '<leader>fw', ':Telescope grep_string<cr>', { desc = 'Grep string' })
 
   -- git navigation
-  map('n', '<leader>ggc', ':Telescope git_commits<cr>')
-  map('n', '<leader>ggs', ':Telescope git_status<cr>')
+  map('n', '<leader>ggc', ':Telescope git_commits<cr>', { desc = 'Git commits' })
+  map('n', '<leader>ggs', ':Telescope git_status<cr>', { desc = 'Git status' })
 end
 
 return M
diff --git a/lua/cosmic/plugins/terminal/mappings.lua b/lua/cosmic/plugins/terminal/mappings.lua
index ed221dd..1b18aa5 100644
--- a/lua/cosmic/plugins/terminal/mappings.lua
+++ b/lua/cosmic/plugins/terminal/mappings.lua
@@ -1,8 +1,8 @@
 local map = require('cosmic.utils').map
 
-map('n', '<C-l>', ':FloatermToggle<CR>')
-map('t', '<C-l>', [[<C-\><C-n>]])
-map('t', '<C-w>l', [[<C-\><C-n>:FloatermNext<CR>]])
-map('t', '<C-w>h', [[<C-\><C-n>:FloatermPrev<CR>]])
-map('t', '<C-w>n', [[<C-\><C-n>:FloatermNew<CR>]])
-map('t', '<C-w>c', [[<C-\><C-n>:FloatermKill<CR>]])
+map('n', '<C-l>', ':FloatermToggle<CR>', { desc = 'Toggle Floaterm' })
+map('t', '<C-l>', [[<C-\><C-n>]], { desc = 'Close Floaterm' })
+map('t', '<C-w>l', [[<C-\><C-n>:FloatermNext<CR>]], { desc = 'Next terminal' })
+map('t', '<C-w>h', [[<C-\><C-n>:FloatermPrev<CR>]], { desc = 'Prev terminal' })
+map('t', '<C-w>n', [[<C-\><C-n>:FloatermNew<CR>]], { desc = 'New terminal' })
+map('t', '<C-w>c', [[<C-\><C-n>:FloatermKill<CR>]], { desc = 'Kill current terminal' })
diff --git a/lua/cosmic/plugins/which-key/init.lua b/lua/cosmic/plugins/which-key/init.lua
index 7438133..0ec46d3 100644
--- a/lua/cosmic/plugins/which-key/init.lua
+++ b/lua/cosmic/plugins/which-key/init.lua
@@ -3,11 +3,41 @@ return {
   { -- color scheme
     'folke/which-key.nvim',
     config = function()
-      require('which-key').setup({
+      local wk = require('which-key')
+      wk.setup({
         -- your configuration comes here
         -- or leave it empty to use the default settings
         -- refer to the configuration section below
       })
+
+      wk.register({
+        ['<leader>'] = {
+          b = {
+            name = '+buffer',
+          },
+          c = {
+            name = '+quickfix',
+          },
+          f = {
+            name = '+file',
+          },
+          h = {
+            name = '+gitsigns',
+            t = {
+              name = '+toggle',
+            },
+          },
+          g = {
+            name = '+goto',
+          },
+          s = {
+            name = '+session',
+          },
+          t = {
+            name = '+tab',
+          },
+        },
+      })
     end,
     event = 'VeryLazy',
     enabled = not vim.tbl_contains(user_config.disable_builtin_plugins, 'which-key'),