My Dev Environment Has 332 Lines of Config. Worth It.
Let me say upfront: you do not need this setup. Most PMs should not have this setup. I am probably spending time optimizing my editor when I should be writing PRDs.
And yet. Here we are.
My daily driver is WSL2 + Wezterm + Neovim. I have 18 plugins across 15 Lua files. My leader key is a comma. I hand-tuned the ANSI colors to match my editor theme. My terminal config is 332 lines long.
This is a post about why I did that, and whether it was actually worth it.
The honest reason
At some point I realized I was constantly context switching. Writing a spec, needing to check how something was actually implemented, opening VS Code, clicking through the file tree, losing my train of thought, going back to the spec. Repeat fifty times a day.
The terminal fixed this. Not because terminals are inherently superior, but because everything I need lives in one place. One window. One keyboard. No alt-tabbing.
Here’s the stack:
| Layer | Tool |
|---|---|
| Environment | WSL2 (Ubuntu) |
| Terminal | Wezterm |
| Shell | Zsh + Starship |
| Editor | Neovim |
Wezterm: where it starts
The first thing I did was make Wezterm open directly into WSL. No Windows terminal, no “wsl.exe” commands, just Linux immediately:
config.default_prog = { 'wsl.exe', '-d', 'Ubuntu', '--cd', '~', '--', 'zsh', '-l' }
Small thing, but it removes one decision from my morning.
The other thing I did was set up a launch menu. I have a shortcut that opens Wezterm, cds into a project, and launches Claude Code in one keystroke. Context switching handled before I’ve had my coffee.
Wezterm also lets you close panes intelligently. Neovim pane? Close instantly, no confirmation. Shell pane? Ask first. You’d be surprised how much this matters when you’re in flow and accidentally hit the wrong keybinding.
wezterm.on('close-pane', function(window, pane)
local process_name = pane:get_foreground_process_name()
if is_editor(process_name) then
window:perform_action(wezterm.action.CloseCurrentPane { confirm = false }, pane)
else
window:perform_action(wezterm.action.CloseCurrentPane { confirm = true }, pane)
end
end)
Neovim: the part people think is excessive
18 plugins is a lot. Here are the ones that actually changed how I work:
Telescope is the one I use most. Fuzzy file finder, live grep across the entire codebase, both mapped to a keybinding. When an engineer tells me “we need to refactor X,” I can find every occurrence in the codebase in about four seconds and give them a more accurate estimate than “sounds like a week.”
vim.keymap.set("n", "<leader>ff", builtin.find_files)
vim.keymap.set("n", "<leader>fg", builtin.live_grep)
I also wired up a custom action that copies the file path to clipboard with Ctrl+Y. One keystroke, paste it into a Jira ticket. Tiny thing, annoyingly useful.
Nvim-Tree sorts files by modification time. Most recently edited files appear at the top. Sounds obvious. The default is alphabetical, which means you have to remember where the thing you just changed lives. I don’t want to remember that.
sort = {
sorter = function(nodes)
table.sort(nodes, function(a, b)
return stat_a.mtime.sec > stat_b.mtime.sec
end)
end,
}
Flash.nvim lets you jump to any word on screen with two keystrokes. Press s, type two characters, jump there. No mouse. No counting how many w presses to get to the function name. Just: I see a word, I go to it.
Render-Markdown renders markdown in place. Headings look like headings. Checkboxes look like checkboxes. I write product specs in markdown, so this matters. Toggle it off when you’re editing, back on when you’re reading.
I have a keybinding that copies content directly to my Obsidian vault, which means my notes, specs, and code snippets all end up in one place without me manually copy-pasting anything.
Neogit is a full git interface inside Neovim. Stage, commit, push, resolve conflicts, all without leaving the editor. If I’m reading code and I spot something wrong, I can fix it and commit in the same flow without touching the terminal.
Rainbow CSV makes CSV files readable. Each column gets a color. You can even run SQL-style queries: :Select a1, a3 where a2 > 100. PMs work with data. This is not a plugin I expected to use this much.
Starship: the prompt matters more than you think
My prompt shows the current directory, git branch, file change count, and command duration for anything that takes more than 2 seconds. The last one is underrated. When I run a build and it takes 45 seconds, I know immediately. When it suddenly takes 3 minutes, I know something changed.
[git_status]
format = '([$all_status$ahead_behind]($style) )'
modified = "!${count}"
staged = "+${count}"
I can see my repo status at a glance without running git status. When you’re bouncing between product work and code fixes all day, this keeps you oriented.
What this actually does for PM work
Three things, concretely:
Scoping gets better. Before I write a ticket, I read the code. Not skimming a PR, actually reading the implementation. grep the codebase, open related files with Telescope, check git history. My estimates are better because I understand what “change X” actually involves.
Prototyping gets faster. When I have an idea I want to test: open terminal, navigate to project (3 keystrokes, I have aliases), find the file, make the change, see the result in a split pane. No IDE startup. No “let me find the right workspace.” The idea-to-validated loop is shorter.
Engineers know I’ve actually looked. When I say “I looked at the implementation,” I mean I read the code, ran it locally, and understood what was happening. This is different from “I looked at the PR description.” People can tell.
The real talk
Is this overkill for most PMs? Yes.
Do you need Neovim to be a good PM? No. Absolutely not. I want to be clear about this.
But if you write code regularly, if you want to understand the technical depth of your product, if you believe that friction between “I have an idea” and “I validated that idea” is a problem worth solving, then a terminal-first setup might be worth trying.
The goal was never to impress anyone. It was to make thinking cheaper.
I work faster now. Not because Neovim is magic, but because I spent the time to configure it into something that fits how I think. The 332 lines of config aren’t overhead. They’re the accumulated decisions of someone who got annoyed enough to fix each thing as it came up.
That’s the actual argument for deep tooling: not that terminals are cool, but that your tools should stop getting in your way.
If you want to try it
Don’t start with Neovim. Start with Wezterm.
Install it, set it to open into WSL, use it for a week. That alone reduces context switching. If you like it, look at Neovim. If you don’t, you’ve still improved your terminal situation.
The full config files are at:
~/.config/wezterm/wezterm.lua~/.config/nvim/lua/plugins/~/.config/starship.toml
Start with telescope.lua and essentials.lua. Those two files give you most of the value with none of the 2 AM configuration spirals.
The rest of it you can add when something annoys you enough to fix it. That’s the whole philosophy, really.