Ramblings of an aging IT geek
← Ramblings of an aging IT geek
tooling

the prompt earns its place on every line

Rebuilding my shell prompt around the few facts I actually check before running a command, and ruthlessly cutting everything else.

A mechanical keyboard glowing next to a terminal

My prompt had quietly turned into a dashboard. Two lines, a Nerd Font icon for the operating system, the battery percentage, the time to the second, a little train of segments in clashing colours, and somewhere in the middle, almost as an afterthought, the directory I was actually standing in. I'd assembled it over years by copying other people's dotfiles, and like most things assembled that way it optimised for looking impressive in a screenshot rather than for being useful at two in the morning.

The thing that finally pushed me to rip it out was a near miss. I ran a git push --force against what I thought was a feature branch and was, in fact, not. The branch name was on screen the whole time. It was the same muted grey as four other segments, third from the left, and my eyes had long since learned to skip the entire region as noise. The information was present and completely invisible, which is the worst state for information to be in.

So I sat down and asked the only question that matters here: before I press Enter on a command, what do I genuinely need to know?

the actual list

The honest answer was short.

  • Where am I. The path, but a sensible amount of it. Not the full forty-character absolute path, and not just the leaf either, because config could be anywhere.
  • What branch, and is it dirty. Force-push aside, the dirty state tells me whether I'm about to do something I'll need to clean up.
  • Did the last command fail. Not the exit code on every line forever, just a clear signal when something went wrong.
  • Am I somewhere I shouldn't be. Root, a production context, an SSH session into a box that isn't mine.

That's it. Battery, time, the OS icon, the username on my own laptop where it never changes: none of it earns a place on a line I read several hundred times a day. If I want the time I'll look at the clock. If I want the battery I have a perfectly good menu bar that already shows it.

building it with starship

I'd been using a hand-rolled PROMPT in zsh, which was part of the problem, because editing it meant remembering parameter expansion flags I look up every single time. I moved to Starship, mostly because the configuration is a flat TOML file I can reason about, and because the git status module already does the expensive work without making me shell out to git myself on every prompt.

The config that came out the other side is almost aggressively boring.

format = """
$directory\
$git_branch\
$git_status\
$cmd_duration\
$character"""

[directory]
truncation_length = 3
truncate_to_repo = true
style = "bold cyan"

[git_branch]
format = "[$branch]($style) "
style = "bold purple"

[git_status]
style = "bold yellow"

[cmd_duration]
min_time = 2000
format = "took [$duration]($style) "

[character]
success_symbol = "[›](bold green)"
error_symbol = "[›](bold red)"

The branch is now bold purple, the only purple thing on the line. It is impossible to miss. The directory truncates to the repo root and shows three components, which is the right amount roughly always. The prompt character is a single that goes red when the last command failed, which replaced an entire status segment with one bit of colour. And cmd_duration only appears when something took more than two seconds, so I get a gentle "that build took 47 seconds" without a permanent timer cluttering the line.

A terminal showing a minimal two-symbol prompt

the part I nearly skipped

The single most valuable thing I added wasn't a built-in module. It was a custom block that screams when I'm somewhere dangerous. SSH sessions get a host indicator, root gets an unmissable marker, and I wired a tiny module to the kubectl context so that a production cluster turns the whole left edge of the prompt a colour I associate, viscerally, with stopping and reading carefully.

[kubernetes]
disabled = false
format = '[$context](bold red) '
kubernetes.contexts
context_pattern = "prod.*"
style = "bold red bg:dark_red"

The logic is the same as a good error message: the cost of a false alarm is a moment of attention, the cost of a missed signal is a force-push to main. So I bias the whole thing towards shouting when the stakes are high and staying silent when they aren't.

what I noticed afterwards

The prompt is faster, which I expected, because there's simply less to compute. What I didn't expect was that I started reading it again. When a line is mostly empty, the things that do appear carry weight. The branch name isn't competing with five other segments for my attention, so I actually see it. A dirty repo is now a thing I notice rather than a thing I discover later with a confused git stash.

There's a general lesson buried in here that I keep relearning in different costumes. Adding information to a display feels like making it more useful, and almost always makes it less so, because attention is the scarce resource and you've just spent it. The prompt that tells me what I need is the one that tells me almost nothing, most of the time, and then says the one thing that matters loudly enough that I can't scroll past it. Mine's been like that for a fortnight now and I haven't force-pushed anything I regret, which feels like the only benchmark that counts.