If I wanted to recommend to someone the min-maxed, highest density thing they could add to their prompt, it would simply be the time your current prompt appeared + the amount of time the last command you ran took.
These two pieces of information together make it very easy for you (or your local sysadmin (or an LLM looking over your digital shoulder)) to piece together a log of exactly what happened when. This kind of psuedo-non-repudiation can be invaluable for debugging sessions when you least expect it.
This was a tip I distilled from Michael W. Lucas's Networking for System Administrators a few years ago, which remains my preferred recommendation for any developers looking to learn just enough about networking to not feel totally lost when talking to an actual network engineer.
Bonus nerd points if you measure time in seconds since the UNIX epoch. Very easy and fast to run time delta calculations if you do that:
[0 1719242840] $ echo "foo"
[0 1719242905] $ echo "fell asleep before hitting enter" && sleep 5
[5 1719242910] $
[1]: https://github.com/hiAndrewQuinn/shell-bling-ubuntu > history | get 82076
╭─────────────────┬──────────────────╮
│ start_timestamp │ 2025-06-24 16:46 │
│ command │ mpc play │
│ cwd │ /home/work │
│ duration │ 1ms │
│ exit_status │ 0 │
╰─────────────────┴──────────────────╯
It's really nice, because it doesn't just tell you time between command executions (or rather time between commands finishing), but the actual runtime duration of the command. history | where exit_status == 127 | last | get duration
2sec 410ms
The syntax ends up very clean looking since the data going through the pipes is typed, and the error messages are top notch × Types 'duration' and 'int' are not compatible for the '-' operator.
╭─[entry #47:1:2]
1 │ (history | where exit_status == 127 | last | get duration) - 10
· ───┬─── ┬ ─┬
· │ │ ╰── int
· │ ╰── does not operate between 'duration' and 'int'
· ╰── duration
╰────
(fingers crossed hn doesn't mangle that...)In fact, I only set up Starship when I started to do more pairing. It wasn’t for my benefit as much as it was for those watching my screen and checking the work, especially when operating on prod and confirming what we wanted to run. I just load up a separate terminal app for that so I don’t have to walk people through my setup.
For example:
…/.config master on AWS_Prod (use2)
starship.toml: [aws]
format = 'on [($profile )(\($region\) )]($style)'
style = 'bold #B23D2F'
symbol = " " <- cloud symbol
[aws.region_aliases]
us-east-1 = 'use1'
us-east-2 = 'use2'
For example, I don’t expect running scripts/build.sh to modify tracked files in the repo. Seeing part of the prompt go from “” to “?2!3” (two untracked, three changed files) makes that glaringly obvious.
And the Branch is also an unintrusive reminder that you are in a path under versioncontrol.
`git status` to know git stuff. `pwd` for the current working directory, etc
I also don't use aliases like `gs` or `..`
One good thing about having a very minimal setup is that you feel at home anywhere.
It wasn't always like this. I used many, many prompts and shell tools over the decades. The only tool that stood the test of time is tmux.
I can sit down at (or ssh into) any machine and be basically just as productive, and it also turns out that I just always want to know more than nicely fits into the prompt anyways.
There's something to be said for accepting the defaults of a tool, and learning to use them well. Customization is powerful, but... I think most times it's not the right call until you're already an expert in the tool at hand.
For example if I have say 3 worktrees open in 3 seperate tmux tabs and are context switching between them (very common when reviewing multiple PRs from my devs) Sometimes i will get the tabs mixed up, which worktree is where etc and just autopilot a bunch of commands meant for one tree into a different one and its quite annoying to clean up.
The prompt has generally stopped me from doing that.
Usually, there will be from 2 to 8 panels of different sizes.
This gives me spacial short term memory: I know what each shell is by the panel position.
I can zoom on then to bring them full screen (ctrl+b z) if I'm going to do anything that requires more space, then zoom out to the panel arrangement when I'm done.
Sometimes I'll name prompts (eg `PS1='stg$ '`), specially when working with ssh, but that's rare.
What inspired me to work this way was this video on the acme editor: https://www.youtube.com/watch?v=dP1xVpMPn8M
tmux comes from BSD rather thsn GNU/Linux, or Windows
What is the default shell in OpenBSD
starship does not support it
starship init ksh
ksh is not yet supported by starship.
For the time being, we support the following shells:
* bash
* elvish
* fish
* ion
* powershell
* tcsh
* zsh
* nu
* xonsh
* cmd
Please open an issue in the starship repo if you would like to see support for ksh:
https://github.com/starship/starship/issues/new
Sort of contrary to that I really enjoy the maximalist shells. A computer should be fun to use!
So if you have
``` src/components/Button.vue src/components/ButtonGroup.vue ```
And you type `nvim s/c/G<Tab>` it’ll expand to the second file’s path.
I’m a researcher and work on small projects with 1-3 people (most of the time it’s just me prototyping stuff alone). I then tend to work on a branch for weeks at a time, so the git branch provides very little information compared to the space it takes in a prompt.
If I was switching branches every 5min, it would be useful.
I found out that with this verify-and-forget step, I work much more efficiently.
As a result, my workflow becomes independent of the machine I work on, because I become the tool, not my setup. After that point, only having a "$" at the beginning of the line is enough.
Of course everyone have their own choices, and YMMV.
Also, I somehow worked in special characters for Python and other things that get screwed up if I don’t have the right nerd font installed on the system.
Even for cases where I need to use old versions, I don’t need a reminder of that every time I run a command.
It isn't that useful but I do glance it when I'm working on dependencies and to ensure the context between a terminal session and pycharm's interpreter match.
The information doesn't cloud the prompt for me though, as it is right justified and I don't really think about time to load, as the machines are relatively recent Apple Silicon.
That way you only have to look at it when you need it, and you can also figure out what you were doing last week/month/year if necessary.
It's a personal machine and should be treated as disposable. Doing anything less is fairly irresponsible.
So sure - turn on timestamps for your ssh bastion (although it should be in the logs already...), or turn them on for the ci/cd pipeline (not that you should need them there anyways, since it should be dumping tons of timing info already).
But a personal machine? Plain ol' ">" is plenty.
Not that there's anything wrong with a maximal prompt either... I've definitely done the "configure all the powerline settings!" thing. But I also don't mind a simple ">" or "#".
You can always time your commands with "time".
Something like
export HISTFILESIZE=
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "
shopt -s histappend
really ought to be default in bash.It's not as clear why you need it in the interactive prompt.
It sounds silly, but it has saved my butt more than once. Especially if you have bugs that e.g. only show up once per hour on the hour, and are otherwise fine.
Here's one zbell implementation, not sure it's the original but it looks like it does the trick: https://gist.github.com/oknowton/8346801
I developed the tool myself, and it's at https://git.sr.ht/~bayindirh/nudge if you feel like checking it out.
If you want to host the whole push notification infrastructure, you can look at https://ntfy.sh which also can be integrated with cURL.
int history_write_timestamps
If non-zero, timestamps are written to the history file, so they can be preserved between sessions. The default value is 0, [...]
So this isn't true by default on many machines unless it is explicitly turned on. Once you do have it on, of course, then I agree.Personally, over time, I have stopped caring too much about prompt customization. I concluded that, no matter how carefully you curate your prompt, 90% of the information shown will be irrelevant 90% of the time*. After a while, your brain will start perceiving this as visual clutter and filter it out, to the point you may even forget the information is there, right in front of your eyes.
And for the things that matter, you probably need more details than any prompt can show you. E.g. are there changes in your git branch? Ok there are, good to know, but which files have changed? Just knowing that there are changes is not really actionable information. You need to run additional commands to get actionable details.
* the numbers are completely arbitrary, but you get the picture
I played with Starship for an hour this morning - the joys of 50 person planning meetings - but ultimately uninstalled it. I did like some of its options like command timing and success/error, but all the tool versions ultimately just felt like noise. Not worth the effort to maintain a complex custom config to trim it down to what I'd want.
I agree there's a lot of noise that seems to be there by default.
For most of my career I used a very simple PS1:
export PS1="\[\033[1;32m\][\t \u@\h \w]\\$\[\033[0m\] "
timestamp, who I am, what box I'm on, where I am.I've tried prompts in the past, and they mostly annoyed me, or never showed me useful information. I've been a happy starship user for several years now. I've got the config tweaked so that it only shows me things I specifically care about. It's lightning fast.
I only emit it if the prior command fails, too, so it doesn't clutter things the 90% of the time things are working.
» true
» false
(last command returned 1.)
»
I also translate signals, so I get "last command exited on SIGSEGV", or so.It's also useful the other way: when a program emits and error and exits with "success".
That was my prompt when it was written in zsh. Sort of like TFA, I've since moved to Rust:
https://github.com/thanatos/dotfiles/blob/master/zsh-prompt-...
I think (if I am reading TFA's code right) unlike the article, I'm using zsh's module functionality, so the Rust here is a .so that is loaded directly into the shell's memory. (I.e., I do not have to fork/exec a separate Rust bin to compute the prompt, though I think zsh might fork-but-not-exec for computing the prompt itself.)
The latter is, of course, somewhat more complicated in some senses. (Esp. on macOS, which work forces me to use, where dlopen(2) is just utterly insane.)
For example the following prints the exit code in green if zero, in red otherwise:
PS1='\[\e[$(($??31:32))m\]$? \[\e[39m\]'
My shell customization is largely throwing Starship in (so it looks the same on all the machines I use -- Ubuntu servers at work, macOS at home, nixOS/Fedora/etc. servers for personal use.) and a starship.toml I wrote once and now leave alone.
I think these kinds of over-optimization rabbit holes are a good learning experience, but I compare it to woodworking. A woodworker just starting out will spend most of his/her time building or refining the tools they need, learning techniques, coming up with ideas/designs and testing them, etc. But eventually the point comes where you have to get Real Work done and the tools and jigs have to wait until the weekend.
Linux is still my favorite desktop OS, but these days I just run Debian and KDE because "free time" is not a thing I have anymore and I care more about getting things done than having the most optimal computing experience.
For a while, I tried a couple of Christmas tree prompts which included all kinds of condensed Git status and other bells and whistles, but eventually tired of them and settled on:
- Exit status of the previous command, if nonzero.
- Current time, HH:MM, 24 hour format.
- user@host, red if euid 0, green otherwise.
- Current directory, shortened if the path has three or more elements, with home directory recognition.
- Current directory, full path, echoed as hardstatus and hence appearing in the terminal window title.
- The name of the current branch if within a Git repo.
- Prompt character, dollar/hash sign.
All those elements are meaningful to me, inasmuch as I can quickly orient myself using that information and explore further if I notice anything out of the ordinary.
I'm pretty sure that megaprompt programs like Starship could produce the above, but I like obtaining a familiar prompt with a minimum of external dependencies, and so have written it all in Bash, then ported to Zsh and various Korn shells, which was quite tricky. It probably wouldn't work on Xenix 286, but anything newer has a fighting chance.
I've tried prompts in the past, and they mostly annoyed me, or never showed me useful information. I've been a happy starship user for several years now. I've got the config tweaked so that it only shows me things I specifically care about. It's lightning fast.
That said my vimrc is 2 lines that i can configure manually, I don't touch bash config from Debian defaults and my fish config is vanilla save for a handful of functions because I'm a lazy. My ssh config is pretty heavily customized but mostly around what keys/usernames to default to for which hosts (see previous about lazy).
A few years ago I progressed to having the current directory in there.
The thought of running a child process to create my prompt every time I hit enter doesn't feel right.
It also gives me the current branch in a directory that has git, just so I'm sure of what I'm working on-- but most of the time that's handled by whatever editor I'm using.
By default my prompt is a shows me the current directory, the time, and a single character '%'. If I set something in my environment for which I need to be contextually aware - i.e if I have KUBECONFIG or OS_CLOUD - then the prompt is updated with the detail. Similar for languages - it'll automatically show me the version of Go or Python or whatever based on a few factors, all of which I can control.
The reason I love Starship is that it's made all this very, very easy to configure - instead of having to wade through arcane Zsh configuration or additional plugins, Starship makes it easy. It also adds negligible overhead to initialisation, especially when done so via evalcache [0]
Love the performance. Written in Rust and compiled to binary, it's _much_ faster than either python-based powerline, the bash-shell-based ohmybash and zshell-based ohmyzsh and spaceship.
You can use it for zsh, bash, sh, fish. but you can also use it for both MS Windows CMD and Powershell. I don't believe any other prompt tools can do all at the same time. And a single config file can control all of them on your system.
The default config is just that - a default. Too much information? you can change it. dont like icons? you can remove them.
At almost 100 modules to choose from, it's customization options are nearly limitless
My shell prompt is:
: ▶
You don’t need an entire shell prompt customisation framework to be minimal. format = """
$username\
$hostname\
$shlvl\
$directory\
$git_branch\
$git_commit\
$git_state\
$git_metrics\
$git_status\
$package\
$python\
$rust\
$env_var\
$custom\
$cmd_duration\
$jobs\
$time\
$status\
$shell\
$character"""
# clean, simple, minimal
PROMPT='%{%F{red}%}%~ %{%F{yellow}%}% › %{%F{reset_color}%}%'
Given that I do like my shiny prompt, which shows me:
The result of the last command (in green, red, or purple)
user@host:currentDirectory
current branch, if in a repo
with the last line showing summary git status, if in a repo, and background jobs, I suspect I might be their market, but I cannot see a why anywhere.(Green: Last command good, e.g., exit 0) (Red: Last command non-zero exit, with a special indicator if it was interrupted) (Purple: Last command suspended, and few other things)
It's very minimal while having useful features: - exit codes, even for pipelines - git branch, status (displayed as a dot if your tree is dirty) and ahead/behind counts - command execution time (if above some configurable threshold) - truncated/minified $CWD, always maintaining the git root's name (I sometimes like it, sometimes don't; fortunately, it's very easy to change) - current vi-like mode (I don't use that)
It's very fast and async (prompt repaints don't block your input or running commands), and totals 132 lines of fish (according to cloc[1]). It's also very customisable through variables, which can be declared as universal to instantly change on all sessions you have open.
If you're on fish and like this feature set, definitely give it a shot, or at least look at the code as a base for a bespoke prompt :P
[0]: https://github.com/jorgebucaran/hydro [1]: https://github.com/AlDanial/cloc
Git-aware prompts can't be recommended on Windows, imo.
I try to avoid emulation layers like MSYS2, as much as I'm able.
Also, yes, if git hangs on git show/git diff that sounds like an antivirus problem or a dying hard drive or the first one causing the other one.
git_status - 6ms - "[!?] "
directory - 4ms - "<redacted> "
python - 3ms - "via v3.12.9 (.venv) "
character - <1ms - " "
git_branch - <1ms - "on main "
hostname - <1ms - "<redacted> in "
If I go in to my checked out version of the linux kernel, probably the biggest git project I've got kicking around: git_status - 115ms - ""
directory - 4ms - "linux "
character - <1ms - " "
git_branch - <1ms - "on master "
hostname - <1ms - "<redacted> in "
That's typically the worst I see it.100ms optimization is a lot different for a CPU or a human brain. I'm not defending having the entire system log dumped out on every prompt but a few amenities are worth a few milliseconds computation time for a human.
Besides, I don't see how, for example , having your prompt take those 100ms to print a git branch or status breaks your "flow" yet having to type out the commands yourself and taking longer doing it doesn't.
Its a balance between bloat and and usability like so many other things, but, to me at least, being on either extreme of bloat or extreme-minimalism seems counterproductive.
FWIW, I switched from zsh default to starship and didn't notice any perceptible difference. But I certainly notice when I mess up my git commits!
Don't the layers of frameworks mean that the opposite is true.
I like to keep things very simple and fast, so the directory and the git branch is all I need. I wonder if people really use all that information or if they set it up thinking they need it, but then never do.
[1]: https://git.sr.ht/~jamesponddotco/gosh
[2]: I should probably update that now that I know a “bit” more Go.
I usually like simple prompt, but there is one feature I really like, it's the timestamp. It helps me remember when I did something and how long it tooks.
https://github.com/iloveitaly/dotfiles/blob/master/.config/s...
I know not everyone likes blinged out shells, but if you're a ZSH user, it fits very well into the Prezto/oh-my-zsh model.
This makes a nasty "flashing" effect.
If I keep Enter pressed, the cursor is permanently visible at offset 0 in the lowest line.
If the prompt is ultra-fast (e.g. plain root shell prompt on zsh), it happens less (e.g. only 50% of cases), but as soon as the prompt does anything, it's very visible.
I observe this with many terminals (gnome-terminal, wezterm, kitty, alacritty, xterm).
The only terminal I tried that doesn't have this problem is urxvt, where it looks perfect.
Video repro: https://nh2.me/flashing-cursors-on-newline.mp4
Why, and is there a way around it for those other terminals?
None of the settings from https://sw.kovidgoyal.net/kitty/performance/ seem to affect its appearance.
I just benchmarked 'starship prompt' and when in a directory managed by git, it can take well over 10ms. I imagine with a more advanced configuration it would take even longer. urxvt must be doing something special.
- See current git branch (to not mistakenly work or commit into the wrong branch)
- See git has changes (to stash them before switching branches)
- See the current language/engine version (like go v1.24.2, because i use tools like gvm, sdk, nvm or rustup to switch version in projects and i want feedback that i have the correct/expected language version enabled)
- See that i am on my local or a remote machine and k8s context
That's mostly it. Of course, I can do this by writing my own prompt, but I found out that Starship does this for me, basically out of the box, on any machine and terminal, in a very nice-looking way. Also, I am not a fan of fancy-looking prompts, so visually, Starship fits best for me.
ends up looking like this: https://github.com/bbkane/dotfiles/blob/master/zsh/README_im...
curl <url> | sh
then you could see on your terminal thousands of various tests related to your installation, then several megabytes being downloaded with progress bars, etc.At the very end of the whole process, the whole stuff would vanish into writing PS1="$ " at the end of your ~/.bashrc
Of course, the very same prompt was used whatever your install could be. I think it was some joke making fun of all these crazy and heavy custom prompts all around.
It would be nice to have a comparison and reasons to change from popular tools.
Most shells can probably do everything this can as well and if you're already familiar with the archaic syntax there is probably limited use for you.
For an idea, here is my current config https://github.com/LukasKnuth/dotfiles/blob/main/zsh/.config...
I've always wondered why someone doesn't just bundle a nice looking shell prompt with common nerd fonts and make it the default in a single package you can install.
Run a full screen term on my machine for a good chunk of my workflow and I just like to have time and battery in my term. I render it as ‘(15:35) [80} <hostname> $ ‘ and for boxes without batteries it’s just ‘(15:35) <hostname> $ ‘
Some times I’ll go back through my scroll back and look at the time when I’m trying to figure things out. Or when I run a command that generates a ton of output, I’ll note the time and run the command then later search back to the time in scroll back to start at the top of the log.
None of these are features I truly miss on a vanilla box, I can look at a clock or watch and will put a comment into the scroll back to find later.
Just so I am clear, use your prompts as you see fit — I’m just trying to understand how others work. Thanks!
int history_write_timestamps
If non-zero, timestamps are written to the history file, so they can be preserved between sessions. The default value is 0, [...]
So this isn't true by default on many machines unless it is explicitly turned on.I could find no command line history for Bash when I poked around. I use the fish shell, however, which does embed timestamp data by default - but I rarely think to look there when the detail might be pertinent. C'est la vie.
Maybe it's finally time for me to sit down and write my own shell prompt once and for all. I wonder if I can make it context-aware of fish's editing vs normal mode when vi mode is enabled
https://github.com/joeyagreco/dotfiles/blob/main/.config/sta...
[right prompt docs] https://starship.rs/advanced-config/#enable-right-prompt [transient prompt docs] https://starship.rs/advanced-config/#transientprompt-and-tra...
Starship only supports this in PowerShell for whatever reason.
Edit: Doh. I see what you linked to now. Yea, maybe it does work in more than just PowerShell now?
Transient prompt basically removes your prompt decorations and replaces it with just `>` in your scroll back history in your shell sessions. In my case it's a slightly more complex transient prompt (datetime and exit code of the command), but still greatly simplified.
Makes cut-and-paste of history in to docs and stuff super nice.
EDIT: oh, i misunderstood, its just the prompt at the start of your shell... I dont think ive ever been annoyed at how fast that renders either
Of course the fastest thing is to just not stuff your prompt full of detail.
If I still used bash, starship would be a non-starter for me, in part, since it's fork/execed in the prompt command. Further up this thread someone says that the zsh installation is different and it's a native shared library that gets loaded into zsh. That seems neat.
(The other reason it's a non-starter is that maybe I can stomach sending over a dotfile to various systems, but selecting a platform-specific native binary is too much configuration management to be done to prepare for an SSH session/kubectl exec. Eventually I made my peace with doing this for emacsclient so I could have local editing of remote files, but that's a lot less critical of a piece to miss than something that appears in your prompt. Conceptually, if you want to ship over/config-manage a native binary, you might as well install a better shell, which became a compelling argument to me when I switched to Powershell).
Or maybe many seconds if you have network drives over a slow VPN connection - not working on network drives, just having them connected. Fun to diagnose when you need to get urgent work done while traveling.
git status takes 643ms for github.com/rust-lang/rust
Starship is the first one that hasn't irritated me, in no small part because it's lightning fast, typically only couple of milliseconds to gather and render the prompt.
This is the first time I've been able to stick with one.
Configuring it with home-manager was as simple as:
programs.starship.enable = true;
Wondering if there are any other life-changing tools I'm missing out on...
In particular I'd call out `gron` (make JSON greppable) and `lnav` (Datadog-level log filtering but for local machines and files) as very helpful for dev work.
[1]: https://github.com/hiAndrewQuinn/shell-bling-ubuntu?tab=read...
~