Ultra-fast, customizable shell prompt that won't slow you down

Rendered with
"{path:#89dceb}{rust:#f38ba8:f: 🦀}{git:#f9e2af:f: }\n{ok:#a6e3a1}{fail:#f38ba8} "
Faster than alternatives – Typical prompts render in ~2ms. Starship averages 10-50ms, oh-my-posh 20-100ms.
Zero configuration needed – Works out of the box with sensible defaults. Customize only what you want.
Predictable performance – No async operations, no network calls, no surprises. Your prompt is always instant.
Single binary – Just install and go. No configuration files required unless you want them.
Context-aware – Automatically detects git repositories, Rust/Node/Python projects, and shows only relevant info.
1. Install
cargo install prmt
2. Add to your shell (pick one)
Bash – Add to ~/.bashrc:
# Simple with named colors
PS1='$(prmt --code $? "{path:cyan} {git:purple} {ok:green}{fail:red} ")'
# Explicit shell wrapping (recommended for prompt usage)
PS1='$(prmt --shell bash --code $? "{path:cyan} {git:purple} {ok:green}{fail:red} ")'
# Or with hex colors for precise theming
PS1='$(prmt --code $? "{path:#89dceb} {git:#f9e2af} {ok:#a6e3a1}{fail:#f38ba8} ")'
Zsh – Add to ~/.zshrc (auto-detected by default; --shell zsh forces wrapping):
setopt PROMPT_SUBST
# Simple with named colors
PROMPT='$(prmt --shell zsh --code $? "{path:cyan} {git:purple} {ok:green}{fail:red} ")'
# Or with hex colors for precise theming
PROMPT='$(prmt --shell zsh --code $? "{path:#89dceb} {git:#f9e2af} {ok:#a6e3a1}{fail:#f38ba8} ")'
Fish – Add to ~/.config/fish/config.fish:
function fish_prompt
prmt --code $status '{path:cyan} {git:purple} {ok:green}{fail:red} '
end
3. Reload your shell
exec $SHELL # or open a new terminal
Done! 🎉
Advanced setup (PROMPT_COMMAND, precmd, environment variables)
function _prmt_prompt() {
local last=$?
PS1="$(prmt --code $last '{path:cyan} {git:purple} {ok:green}{fail:red}')"
}
PROMPT_COMMAND=_prmt_prompt
If you already use PROMPT_COMMAND, append _prmt_prompt instead of overwriting it.
PS1='$(prmt --shell bash --code $? "{path:cyan} {git:purple} {ok:green}{fail:red} ")'
function _prmt_lastcommand() {
history | tail -1 | cut -c 8-
}
function _prmt_deleteprompt() {
local prompt=${PS1@P}
local lines=${prompt//[^$'\n']}
local count=${#lines}
tput cuu $((count + 1))
tput ed
}
function _prmt_indicator() {
prmt --shell bash --code ${1:-0} "{ok:green}> {fail:red}> "
}
PS0='\[$(_prmt_deleteprompt)\]$(_prmt_indicator ${LAST_EXIT_CODE}) $(_prmt_lastcommand)\n\[${PS1:0:$((EXPS0=1,0))}\]'
PROMPT_COMMAND='LAST_EXIT_CODE=$?; [ "$EXPS0" = 0 ] && _prmt_deleteprompt && echo -e "$(_prmt_indicator ${LAST_EXIT_CODE})" || EXPS0=0'
This replaces the full prompt with a compact one after the command runs. It relies on tput and Bash 4.4+.
function _prmt_precmd() {
local code=$?
PROMPT="$(prmt --code $code '{path:cyan} {git:purple} {ok:green}{fail:red}')"
}
typeset -ga precmd_functions
precmd_functions+=(_prmt_precmd)
# Add to $PROFILE
function prompt {
prmt --code $LASTEXITCODE '{path:cyan:s} {git:purple:s:on :} {ok:green}{fail:red} '
}
All shells support using PRMT_FORMAT environment variable:
# Bash/Zsh
export PRMT_FORMAT="{path:cyan:r} {rust:red:m:v 🦀} {git:purple}"
PS1='$(prmt --code $?)\$ '
# Fish
set -x PRMT_FORMAT "{path:cyan:r} {python:yellow:m: 🐍} {git:purple}"
# PowerShell
$env:PRMT_FORMAT = "{path:cyan:r} {git:purple}"
Minimal
prmt '{path:cyan:s} {ok:green}{fail:red} '
# Output: projects ❯
Developer
prmt '{path:cyan} {git:purple} {rust:red:s: 🦀} {node:green:s: ⬢} {ok:green}{fail:red} '
# Output: ~/projects/prmt on main 🦀1.90 ⬢20.5 ❯
Identity (via env module)
prmt '{env::USER}@{env::HOSTNAME} {path:cyan:s} {git:purple} {ok:green}{fail:red} '
# Output: zenpie@workbox projects on main ❯
Compact with time
prmt '{time:dim:12h} {path:cyan:s} {git:purple:s} {ok:green}{fail:red} '
# Output: 02:30PM projects main ❯
Full featured with newline
prmt '{path:cyan} {git:purple} {python:yellow:m: 🐍} {time:dim}\n{ok:green}{fail:red} '
# Output: ~/ml-project on develop 🐍3.11 14:30
# ❯
Status-focused
prmt '{path:cyan:s} {git:purple:s:on :} {ok:green:✓}{fail:red:✗} '
# Output (success): projects on main ✓
# Output (failure): projects on main ✗
With exit codes
prmt '{path:cyan} {git:purple} {ok:green:❯}{fail:red::code} '
# Output (success): ~/projects main ❯
# Output (failure): ~/projects main 127
# Install from crates.io
cargo install prmt
# Build from source (Rust 2024 edition required)
cargo build --release
cp target/release/prmt ~/.local/bin/
# Or install directly from source
cargo install --path .
# Verify installation
prmt --version
# Simple format with defaults
prmt '{path} {rust} {git}'
# Output: ~/projects 1.89.0 master
# Format with types and styles
prmt '{path::a}' # /home/user/projects (absolute path)
prmt '{path::r}' # ~/projects (relative with ~)
prmt '{path::i}' # ~/p/projects (parent initials, last segment preserved)
prmt '{path::u}' # ~/prjcts (interior vowels stripped)
prmt '{path::s}' # projects (short - last dir only)
prmt '{rust:red:s}' # 1.89 in red (short version)
prmt '{rust:red:m:v:}' # v1 in red (major version with prefix)
prmt '{path:cyan:s:[:]}' # [projects] in cyan
prmt '{git:purple::on :}' # on master in purple
# Simplified formats with omitted parts
prmt '{rust::::!}' # 1.89.0! (default style/type, suffix only)
prmt '{rust:::v:}' # v1.89.0 (default style/type, prefix only)
prmt '{path::::]}' # ~/projects] (suffix only)
prmt '{git:::on :}' # on master (prefix only)
# Add your own icons with prefix
prmt '{rust::: 🦀}' # 🦀1.89.0 (default color)
prmt '{node:green:: ⬢}' # ⬢20.5.0 in green
prmt '{python:yellow:: 🐍}' # 🐍3.11.0 in yellow
# Or add spacing with suffix for better readability
prmt '{rust::: 🦀 }' # 🦀 1.89.0 (space after icon)
prmt '{node:green:: ⬢ }' # ⬢ 20.5.0 (space after icon)
# Using short format aliases
prmt '{path:cyan:s} {rust:red:m:v:}' # projects v1 (both in color)
prmt '{git::s:on :}' # on master (short format with prefix)
# No style with type
prmt '{path::s}' # projects (no color, short)
prmt '{path::a}' # /home/user/projects (no color, absolute)
prmt '{rust::m:v}' # v1 (no color, major with prefix)
# With exit code indicators (requires --code flag)
prmt --code $? '{path:cyan} {ok:green}{fail:red}'
# Output (success): ~/projects ❯ (green)
# Output (failure): ~/projects ❯ (red)
# Fast mode (no version detection)
prmt --no-version '{path:cyan} {rust:red} {node:green}'
# Output: ~/projects (only shows active modules, no versions)
# Custom symbols for ok/fail using type as symbol
prmt --code $? '{path} {ok::✓} {fail::✗}'
# Output (success): ~/projects ✓
# Output (failure): ~/projects ✗
# Show exit code on failure
prmt --code $? '{path} {ok::❯} {fail::code}'
# Output (success): ~/projects ❯
# Output (failure with code 127): ~/projects 127
# Time formats
prmt '{time}' # 14:30 (default 24h)
prmt '{time::24hs}' # 14:30:45
prmt '{time::12h}' # 02:30PM
prmt '{time::12hs}' # 02:30:45PM
prmt '{path:cyan} {time:dim:12h}' # ~/projects 02:30PM (with styling)
{module} - Default everything
{module:style} - Custom style
{module:style:type} - Custom style and type
{module:style:type:prefix} - Add prefix to value
{module:style:type:prefix:postfix} - Add prefix and postfix
# Omitting parts (empty means default)
{module::::suffix} - Default style/type, suffix only
{module:::prefix:} - Default style/type, prefix only
{module:::prefix:suffix} - Default style/type, both prefix/suffix
{module::type} - No style, specific type
{module::type::suffix} - No style, specific type, suffix only
| Module | Detection | Description |
|---|---|---|
path |
Always active | Current directory with ~ for home |
ok |
Exit code = 0 | Shows when last command succeeded (default: ❯) |
fail |
Exit code ≠ 0 | Shows when last command failed (default: ❯) |
git |
.git directory |
Branch name with status indicators |
node |
package.json |
Node.js version |
python |
requirements.txt, pyproject.toml, etc |
Python version |
rust |
Cargo.toml |
Rust version |
deno |
deno.json, deno.jsonc |
Deno version |
bun |
bun.lock, bun.lockb |
Bun version |
go |
go.mod |
Go version |
elixir |
mix.exs |
Elixir version |
env |
Requested variable is set/non-empty | Value of a specific environment variable (format = name) |
time |
Always active | Current time in various formats |
json |
--stdin flag |
Extract values from JSON piped via stdin (format = dot-path) |
Version modules (rust, node, python, etc.):
- full or f - Full version (1.89.0)
- short or s - Major.minor (1.89)
- major or m - Major only (1)
Path module:
- relative or r - Path with ~ for home directory (default)
- absolute, a, or f - Full absolute path without ~ substitution
- initials or i - Parent segments shortened to their first character; last segment kept full (hidden dirs keep the leading .)
- unvowel or u - Interior vowels stripped from each segment; first character kept; segments ≤ 3 chars unchanged
- short or s - Last directory only
Git module:
- full or f - Branch with status (default)
- short or s - Branch name only
- Add +owned (or +o) to show only repos owned by the current user (e.g., {git::full+owned})
Ok/Fail modules:
- full - Default symbol (❯)
- code - Shows the actual exit code number
- Any other string - Uses that string as the symbol (e.g., {ok::✓} shows ✓)
Time module:
- 24h - 24-hour format HH:MM (default)
- 24hs or 24HS - 24-hour format with seconds HH:MM:SS
- 12h or 12H - 12-hour format hh:MMAM/PM
- 12hs or 12HS - 12-hour format with seconds hh:MM:SSAM/PM
Env module:
- The type field is required and must be the environment variable name (e.g., {env::USER} or {env:blue:PATH}).
- The module emits the variable value only when it exists and is non-empty; otherwise it returns nothing so the placeholder is effectively inactive.
- Example for identity: {env::USER}@{env::HOSTNAME}
Json module (requires --stdin):
- Reads JSON from stdin and extracts values using dot-path notation.
- The type field is the dot-path to the value (e.g., {json::.model.id} or {json::name}).
- Supports nested objects ({json::.a.b.c}), array indexing ({json::.items.0}), and the leading dot is optional.
- Strings are returned as-is, numbers and booleans are stringified, null and missing paths produce no output.
- When --stdin is not passed, json placeholders are silently inactive.
Claude Code status line -- pipe JSON context to prmt to display model and context window usage.
Add to your Claude Code settings.json:
{
"statusLine": {
"type": "command",
"command": "prmt --stdin '{path:#89dceb}{node:#a6e3a1:f: [:]}{rust:#f38ba8:f: 🦀}{git:#f9e2af:f: } {json:#d97757:.model.id: :}{json:#f5c2e7:.context_window.used_percentage: :%}'",
"padding": 0
}
}
The format parser validates types at parse time to catch errors early:
# Valid types for each module
prmt '{path::short}' # ✓ Valid
prmt '{path::initials}' # ✓ Valid
prmt '{path::unvowel}' # ✓ Valid
prmt '{rust::major}' # ✓ Valid
prmt '{ok::✓}' # ✓ Valid (custom symbol)
prmt '{fail::code}' # ✓ Valid (shows exit code)
# Invalid types produce clear errors
prmt '{path::major}'
# Error: Invalid type 'major' for module 'path'. Valid types: relative, r, absolute, a, f, initials, i, unvowel, u, short, s
prmt '{git::major}'
# Error: Invalid type 'major' for module 'git'. Valid types: full, short
| Module | Default Color | Can Override |
|---|---|---|
path |
cyan | Yes |
ok |
green | Yes |
fail |
red | Yes |
git |
purple | Yes |
node |
green | Yes |
rust |
red | Yes |
python |
yellow | Yes |
go |
cyan | Yes |
deno |
- | Yes |
bun |
- | Yes |
time |
- | Yes |