Jesse A. Green / notebook

Starship — Administrator & Developer Guide

Generated May 2026 from starship/starship at c8391a9

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Starship is a minimal, blazing-fast, infinitely customizable cross-shell prompt written in Rust (2024 edition, MSRV 1.90). It detects your development environment automatically and renders a rich, informative prompt across every major shell. Version 1.24.2, ISC license.

This guide covers architecture, configuration internals, build processes, performance tuning, security considerations, and developer workflows — everything needed to deploy, operate, maintain, or contribute to Starship at the source level.


1. Architecture Overview

1.1 High-Level Execution Model

Starship operates as a stateless CLI binary invoked by shell hooks before each prompt render. There is no daemon, no background process, and no persistent state between invocations. The full lifecycle for every prompt:

  1. The user runs eval "$(starship init <shell>)" once per session, which registers shell-specific hooks (precmd, preexec, or equivalent)
  2. Before each prompt display, the shell hook calls starship prompt with properties including exit status, command duration, number of jobs, terminal width, and keymap
  3. Starship reads ~/.config/starship.toml (or $STARSHIP_CONFIG), builds a Context struct
  4. The Context scans the current directory, discovers git repositories, detects language/tool presence via file extensions, filenames, and folder names
  5. Each module in PROMPT_ORDER is invoked — modules return None if their detection criteria are not met, or Some(Module) with rendered segments
  6. Modules execute in parallel via rayon when safe; shared state (e.g., between git_status and git_metrics) is coordinated through parking_lot mutexes
  7. StringFormatter processes format strings through a PEG parser
  8. The final prompt string is assembled and printed to stdout
┌──────────────────────────────────────────────────────────┐
│  Shell (bash/zsh/fish/pwsh/elvish/nu/cmd/tcsh/xonsh)    │
│  eval "$(starship init <shell>)"                         │
│  ↓ precmd hook                                           │
│  starship prompt --status=$? --cmd-duration=...          │
└──────────────┬───────────────────────────────────────────┘
               │
┌──────────────▼───────────────────────────────────────────┐
│  main.rs  →  CLI dispatch (clap derive)                  │
│  ↓                                                       │
│  context.rs  →  Context { shell, env, dir, git_repo }    │
│  ↓                                                       │
│  config.rs   →  StarshipConfig (TOML parse)              │
│  ↓                                                       │
│  print.rs    →  For each module in PROMPT_ORDER:         │
│    ├── modules/<name>.rs  →  detect + render             │
│    │   ├── config from configs/<name>.rs                 │
│    │   ├── StringFormatter (formatter/)                  │
│    │   └── exec_cmd for version/status                   │
│    └── rayon parallel execution                          │
│  ↓                                                       │
│  segment.rs  →  Assemble final ANSI string               │
│  ↓                                                       │
│  stdout                                                  │
└──────────────────────────────────────────────────────────┘

Note

Starship is a pure CLI tool. There are no API endpoints, no HTTP server, no web interface, no background daemon. Every invocation is a fresh process that reads config, scans the environment, renders, and exits.

1.2 Core Subsystems

Subsystem Entry Point Responsibility
CLI src/main.rs Clap-based command dispatch for all subcommands
Library root src/lib.rs Re-exports for library consumers
Config src/config.rs TOML parsing, ModuleConfig trait, style parsing, StarshipConfig
Context src/context.rs Shell detection, environment capture, git repo discovery, directory scanning
Modules src/modules/mod.rs + src/modules/*.rs 90+ feature modules, each self-contained
Module configs src/configs/mod.rs + src/configs/*.rs One config struct per module with serde defaults
Formatter src/formatter/ PEG-based template engine for format strings
Print src/print.rs Prompt rendering, explain mode, timings, preset application
Init src/init/ Per-shell initialization scripts
Utilities src/utils/ Command execution, file reading, home directory, env vars
Config editing src/configure.rs starship config subcommand — update, toggle, print, edit
Bug report src/bug_report.rs Diagnostic data collection
Logger src/logger.rs File-based logging with session keys and auto-cleanup

1.3 Data Flow: Module Execution

Each module follows a consistent pattern defined by the function signature:

pub fn module<'a>(context: &'a Context) -> Option<Module<'a>>

The module:

  1. Loads its typed config struct (with #[serde(default)] ensuring all fields have fallbacks)
  2. Checks detection criteria — presence of specific files, file extensions, or folder names in the current directory (via DirContents)
  3. If detected, executes any needed external commands (e.g., node --version) with exec_cmd and the configured command_timeout
  4. Creates a StringFormatter from its format string, maps variables to values
  5. Returns Some(Module) with styled segments, or None if detection fails or output is empty

1.4 Parallelism Model

Starship uses rayon for module-level parallelism. The thread pool size is controlled by the STARSHIP_NUM_THREADS environment variable. Most modules are fully independent — they read config, scan files, optionally run a command, and return segments.

The exception is git state: git_status and git_metrics share computed state via parking_lot synchronization primitives. This allows both modules to benefit from a single git repository scan without duplicating work.


2. System Requirements

2.1 Build Requirements

Requirement Minimum Recommended
Rust toolchain 1.90 (MSRV) Latest stable
Rust edition 2024 2024
Cargo Bundled with Rust Latest stable
Git Any recent For shadow-rs build metadata

2.2 Runtime Dependencies

Starship itself is a single static binary with no runtime library dependencies beyond the OS. However, individual modules may shell out to external tools:

Category Examples
Language runtimes node, python, ruby, go, java, rustc, dotnet, elixir, etc.
Package managers npm, cargo, pip, composer, gradle, etc.
Cloud CLIs aws, gcloud, az, kubectl, terraform, etc.
VCS git (also accessed via the gix crate natively)
System tools cmake, docker, vagrant, etc.

These are optional — modules that cannot find their target tool simply return None and produce no prompt segment.

2.3 Supported Shells

Shell Init Script Notes
Bash starship.bash precmd_function hook
Zsh starship.zsh precmd hook
Fish starship.fish fish_prompt function
PowerShell starship.ps1 prompt function override
Elvish starship.elv edit:before-readline hook
Nushell starship.nu env/config integration
Cmd (Clink) starship.lua Lua prompt filter
Tcsh starship.tcsh precmd alias
Xonsh starship.xsh $PROMPT callable

2.4 Platform Support

Platform Status Notes
Linux (x86_64, aarch64) Full Primary platform
macOS (x86_64, aarch64) Full .pkg installer available
Windows (x86_64) Full MSI/Chocolatey installers, deelevate + windows crate deps
FreeBSD Supported Via cargo install
WSL Supported WSLENV detection used in git_status

Windows-specific dependencies in the build:

  • deelevate crate — handles elevation detection
  • windows crate — Win32 API bindings
  • winres — embeds manifest and icon into the executable during build

Unix-specific:

  • nix crate — POSIX API bindings

2.5 Cargo Features

Feature Default Crate Purpose
battery Yes starship-battery 0.11.0 Battery level/status module
notify Yes notify-rust 4.15.0 Desktop notifications (e.g., long-running command alerts)
config-schema No schemars 1.2.1 JSON Schema generation for config validation

Build without optional features:

cargo build --release --no-default-features

Build with schema generation:

cargo build --release --features config-schema

3. Configuration Reference

3.1 Config File Location

Starship reads configuration from a single TOML file. Resolution order:

  1. $STARSHIP_CONFIG environment variable (if set)
  2. ~/.config/starship.toml (XDG default)

The file is parsed on every prompt invocation. There is no config caching between invocations — each process is ephemeral.

Important

Starship also supports JSONC format via jsonc-parser 0.32.3 for the config file, but TOML is the primary and recommended format. The config file path must point to a single file — directory-based config splitting is not supported.

3.2 Root Configuration Keys

These keys are set at the top level of starship.toml, outside any module section:

Key Type Default Description
format String "$all" Main prompt format. $all expands to all modules in PROMPT_ORDER
right_format String "" Right-aligned prompt (shells that support it)
continuation_prompt String (built-in) Prompt shown for multi-line input continuation
scan_timeout u64 30 Directory scan timeout in milliseconds
command_timeout u64 500 External command execution timeout in milliseconds
add_newline bool true Print a blank line before the prompt
follow_symlinks bool (default) Follow symlinks during directory scanning
palette String (optional) None Name of the active color palette
palettes HashMap {} User-defined color palettes (name to color map)
profiles IndexMap {} Named prompt profiles for quick switching
$schema String "" JSON Schema URL for editor validation

The StarshipRootConfig struct is defined in src/configs/mod.rs. The PROMPT_ORDER constant (also in src/configs/mod.rs) defines the default expansion order for $all. The FullConfig struct aggregates the root config with all module configs for serialization.

3.3 Module Configuration Pattern

Every module has a corresponding config struct in src/configs/<module>.rs. All config structs share these conventions:

  • #[serde(default)] on every struct — ensures missing keys get sensible defaults
  • #[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))] — conditional JSON Schema derivation
  • Fields typically include: format, style, symbol, disabled, detection arrays (detect_files, detect_extensions, detect_folders)

Example pattern (representative):

[module_name]
format = "via [$symbol($version)]($style) "
symbol = "X "
style = "bold blue"
disabled = false
detect_files = ["Makefile"]
detect_extensions = ["mk"]
detect_folders = []

3.4 Style System

Styles are parsed in src/config.rs. A style string is a space-separated list of tokens:

Text attributes:

Token Effect
bold Bold text
italic Italic text
underline Underlined text
dimmed Dimmed/faint text
inverted Swap foreground and background
blink Blinking text
hidden Hidden text
strikethrough Strikethrough text

Color specification:

Format Example Description
Named color red, green, blue 16 standard terminal colors
Bright variant bright-red, bright-green Bright/bold color variants
Hex #FF5733 24-bit RGB color
ANSI 256 123 0-255 ANSI color index
fg:<color> fg:red, fg:#FF5733 Explicit foreground (default if no prefix)
bg:<color> bg:blue, bg:#003366 Background color
prev_fg prev_fg Reference previous segment's foreground
prev_bg prev_bg Reference previous segment's background

Style strings compose naturally: bold italic fg:#FF5733 bg:black produces bold italic text with a custom orange foreground on a black background.

3.5 Format String Engine

The StringFormatter in src/formatter/string_formatter.rs processes format strings using a PEG grammar defined in src/formatter/spec.pest.

Syntax elements:

Syntax Meaning
$variable Insert variable value
[$text](style) Apply style to text
($conditional) Only render if all variables inside are non-empty
${module.sub} Reference a sub-module variable
\\$ Literal $ (escaped)

Format model types (from src/formatter/model.rs):

  • TextGroup — a styled group of format elements
  • FormatElement — individual text, variable, or conditional
  • StyleElement — style specification attached to a text group

Version formatting is handled separately by VersionFormatter in src/formatter/version.rs:

Variable Meaning
${raw} Full version string as returned by the command
${major} Major version component
${minor} Minor version component
${patch} Patch version component

Example: version_format = "v${major}.${minor}" renders v3.12 from Python 3.12.1.

3.6 Custom Color Palettes

Palettes allow defining named colors that can be referenced in any style string:

palette = "catppuccin_mocha"

[palettes.catppuccin_mocha]
rosewater = "#f5e0dc"
flamingo = "#f2cdcd"
pink = "#f5c2e7"
mauve = "#cba6f7"
red = "#f38ba8"

Once a palette is active, its color names become valid in any style string: style = "bold mauve".

3.7 Prompt Profiles

The profiles key in root config stores named prompt configurations as TOML strings. These allow quick switching between different prompt layouts without editing the config file. The profiles field uses IndexMap<String, String> to preserve insertion order. A separate internal_profiles field exists but is skipped during serialization.

3.8 Config Editing Commands

The src/configure.rs module provides CLI-based config manipulation:

Command Action
starship config Open config in $VISUAL or $EDITOR
starship config <key> Print a config value
starship config <key> <value> Set a config value
starship toggle <module> Toggle a module's disabled state
starship print-config Dump the full resolved config

The config file is edited in-place using toml_edit 0.25.11, which preserves formatting, comments, and ordering.


4. Deployment & Scaling

4.1 Installation Methods

Shell script (Linux/macOS):

curl -sS https://starship.rs/install.sh | sh

The install script at install/install.sh handles platform detection, binary download, and placement.

Package managers:

Platform Command
Cargo cargo install starship --locked
Homebrew brew install starship
Scoop (Windows) scoop install starship
Chocolatey choco install starship
winget winget install --id Starship.Starship
macOS .pkg Built via install/macos_packages/ scripts
Windows MSI Built via install/windows/ (WiX-based)

4.2 Shell Integration

After installing the binary, each shell needs its init hook. The init scripts are embedded in the binary and emitted by starship init <shell>:

Bash — add to ~/.bashrc:

eval "$(starship init bash)"

Zsh — add to ~/.zshrc:

eval "$(starship init zsh)"

Fish — add to ~/.config/fish/config.fish:

starship init fish | source

PowerShell — add to $PROFILE:

Invoke-Expression (&starship init powershell)

Elvish — add to ~/.elvish/rc.elv:

eval (starship init elvish)

Nushell — generate config files:

mkdir ~/.cache/starship
starship init nu | save -f ~/.cache/starship/init.nu

Cmd (Clink) — install into Clink scripts directory:

starship init cmd

Tcsh — add to ~/.tcshrc:

eval `starship init tcsh`

Xonsh — add to ~/.xonshrc:

execx($(starship init xonsh))

The init logic in src/init/mod.rs uses StarshipPath to resolve the binary location and generates the appropriate hook registration for each shell.

4.3 Building from Source

git clone https://github.com/starship/starship.git
cd starship
cargo build --release

The release binary is at target/release/starship (or target/release/starship.exe on Windows).

Release profile (from Cargo.toml):

  • codegen-units = 1 — maximum optimization (slower build, faster binary)
  • lto = true — full link-time optimization
  • strip = true — strip debug symbols

Bench profile:

  • codegen-units = 16 — faster builds for benchmarking
  • lto = thin — lighter LTO
  • strip = false — keep symbols for profiling

4.4 Build Script Details

build.rs performs three tasks:

  1. shadow-rs integration — embeds build metadata as compile-time constants:

    • PKG_VERSION — crate version from Cargo.toml
    • SHORT_COMMIT — abbreviated git commit hash
    • BRANCH — git branch name
    • TAG — git tag (if on a tag)
    • RUST_VERSION — Rust compiler version used
    • RUST_CHANNEL — stable/beta/nightly
    • BUILD_RUST_CHANNEL — channel used for the build itself
    • BUILD_TIME — timestamp of build
    • CLAP_LONG_VERSION — formatted version string for --version
  2. Preset embedding — reads TOML preset files from docs/public/presets/toml/ and embeds them into the binary at compile time, enabling starship preset <name> without file I/O at runtime.

  3. Windows resources — winres embeds a Windows application manifest and icon into the .exe.

4.5 Packaging

macOS .pkg: Scripts in install/macos_packages/ build a signed macOS installer package.

Windows MSI: install/windows/ contains WiX Toolset definitions for building a Windows Installer package.

Chocolatey: Windows package definition also in install/windows/.

4.6 Distribution at Scale

Starship is a single binary with no server component. "Scaling" means distributing the binary to workstations. Common approaches for organizations:

  • Package manager repositories (internal Artifactory, Chocolatey server, Homebrew tap)
  • Configuration management (Ansible, Puppet, Chef) for binary placement + shell rc injection
  • Dotfile repositories with the starship.toml checked in
  • Container base images with Starship pre-installed (useful for dev containers)
  • Shared starship.toml via $STARSHIP_CONFIG pointing to a network-mounted or synced path

5. Operations

5.1 Environment Variables

Tip

All Starship-specific environment variables use the STARSHIP_ prefix. These are the primary operational knobs available without editing the config file.

Variable Purpose Values
STARSHIP_CONFIG Override config file path Absolute file path
STARSHIP_SHELL Override detected shell name bash, zsh, fish, powershell, etc.
STARSHIP_LOG Set log verbosity trace, debug, info, warn, error
STARSHIP_NUM_THREADS Set rayon thread pool size Integer (default: CPU-dependent)
STARSHIP_SESSION_KEY Session identifier for log files String (auto-generated if unset)
VISUAL Preferred editor for starship config Editor command (takes precedence over EDITOR)
EDITOR Fallback editor for starship config Editor command
PWD Current directory fallback Path
WSLENV WSL environment detection Used by git_status for WSL-specific behavior
TERM_PROGRAM Terminal emulator detection e.g., iTerm.app, WezTerm
LC_TERMINAL Terminal detection (alternative) Terminal identifier
TERM_PROGRAM_VERSION Terminal version detection Version string
LC_TERMINAL_VERSION Terminal version (alternative) Version string

5.2 Logging System

The logger (src/logger.rs) writes session-based log files to the platform-specific cache directory:

Platform Log Directory
Linux ~/.cache/starship/
macOS ~/Library/Caches/starship/
Windows %LOCALAPPDATA%\starship\

Log files are named session_<STARSHIP_SESSION_KEY>.log. The session key is derived from STARSHIP_SESSION_KEY if set, otherwise auto-generated per shell session.

Log levels (set via STARSHIP_LOG):

Level Content
error Fatal errors only
warn Warnings and errors
info Informational messages, warnings, errors
debug Detailed debug output
trace Maximum verbosity, includes all internal state

Automatic cleanup: The logger implements old log file cleanup to prevent unbounded disk growth in the cache directory.

Tip

For diagnosing prompt rendering issues, run STARSHIP_LOG=trace starship prompt in the affected directory. The trace output shows every module's detection logic, command execution, and timing.

5.3 CLI Subcommands

The full CLI interface (from src/main.rs, clap derive mode):

Subcommand Purpose
init <shell> Output shell initialization script
prompt Render the prompt (called by shell hooks)
module <name> Render a single module (for debugging)
preset <name> Output or apply a built-in preset
config [key] [value] Read, write, or edit configuration
print-config Print the full resolved configuration
toggle <module> Toggle a module's disabled state
bug-report Generate a diagnostic bug report
explain Print prompt with module explanations
timings Print prompt with per-module timing data
completions <shell> Generate shell completion scripts
session Output a session key
statusline Render status line output
time (Hidden) Timing-related utility
config-schema (Feature-gated: config-schema) Output JSON Schema for config

5.4 Diagnostic Tools

Bug report (src/bug_report.rs):

starship bug-report

Collects system info, shell version, Starship version, config contents, and environment details into a formatted report suitable for GitHub issues.

Explain mode:

starship explain

Renders the prompt with annotations showing which module produced each segment and why.

Timings:

starship timings

Renders the prompt with per-module execution time, sorted by duration. Essential for identifying slow modules.

Single module test:

starship module git_status

Renders only the specified module — useful for isolating issues.

5.5 Presets

Presets are complete starship.toml configurations embedded at compile time from docs/public/presets/toml/. Apply with:

starship preset <preset-name> -o ~/.config/starship.toml

List available presets:

starship preset --list

Note

Applying a preset overwrites the entire config file. Back up your existing config first if you have customizations. Presets can also be piped: starship preset <name> | cat to inspect before applying.


6. Performance

6.1 Architecture Decisions for Speed

Starship's performance budget is tight — every millisecond of prompt render time is directly felt by the user. Key design choices:

  1. Rust with release LTO — codegen-units=1 and lto=true in the release profile maximize binary optimization at the cost of slower compilation
  2. Parallel module execution — rayon processes independent modules concurrently across available cores
  3. Native git via gix — gix 0.81.0 provides in-process git operations (revision parsing, status, SHA computation) without shelling out to the git binary for many operations
  4. Lazy evaluation — std::sync::LazyLock defers expensive version command execution until the value is actually needed
  5. Directory scan with timeout — DirContents::from_path_with_timeout() aborts scanning after scan_timeout milliseconds, preventing hangs on large or network-mounted directories
  6. Command timeout — every external command invocation (exec_cmd) is bounded by command_timeout milliseconds
  7. Single-pass rendering — the PEG parser processes format strings in a single pass

6.2 Tuning Parameters

Parameter Location Default Effect
scan_timeout starship.toml root 30 ms Max time for directory content scanning
command_timeout starship.toml root 500 ms Max time for any external command
STARSHIP_NUM_THREADS Environment CPU-dependent Rayon thread pool size

For slow prompts, the standard diagnostic workflow:

  1. Run starship timings to identify the slowest modules
  2. Increase command_timeout if legitimate commands are being killed prematurely
  3. Decrease scan_timeout if directory scanning is slow (network mounts, huge repos)
  4. Disable modules you do not need: set disabled = true under the module section
  5. Set STARSHIP_NUM_THREADS to match available cores if the default is suboptimal

6.3 Known Performance Considerations

Git operations in large repositories: The git_status module can be slow in repositories with many files or large working tree changes. The gix-based implementation is faster than shelling out, but still bounded by repository size.

Network-mounted directories: Directory scanning (DirContents) on NFS, SMB, or SSHFS mounts can block. The scan_timeout is the primary defense — set it aggressively low (10-15ms) on known-slow mounts and accept that some detection may be skipped.

PowerShell on Windows: PowerShell's process startup overhead amplifies Starship's per-prompt cost. This is a known issue (GitHub #2057). The command_timeout default of 500ms may be tight for some tools on Windows.

WSL git interop: The WSLENV detection in git_status handles the case where git operations cross the WSL/Windows boundary, which can be significantly slower than native operations.

6.4 Profiling

For development profiling, use the bench Cargo profile:

cargo build --profile bench

This uses codegen-units=16, lto=thin, and strip=false — faster build times with debug symbols preserved for profilers like perf, flamegraph, or cargo-instruments.


7. Security

7.1 Threat Model

Starship's security surface is minimal by design:

  • No network access — Starship never makes network connections. All data comes from local filesystem, environment variables, and local command execution
  • No persistent state — no databases, no caches between invocations, no IPC
  • No elevated privileges — runs as the invoking user with no setuid or capabilities
  • Read-only by default — only starship config writes to the filesystem (the config file only)

Warning

Starship executes external commands (version checks, git operations, etc.) with the permissions of the invoking user. A malicious starship.toml placed in a shared or cloned repository could configure modules to trigger unintended command execution if the user points STARSHIP_CONFIG to that file. Always review untrusted config files before use.

7.2 Configuration Security

The config file (starship.toml) is read from the user's home directory by default. Key security properties:

  • Config is TOML — no code execution in the config parser itself
  • Custom commands in modules (e.g., version commands) are executed via the standard command timeout mechanism
  • toml_edit preserves file structure but does not execute embedded code
  • No config file includes or imports — a single flat file only
  • No remote config fetching — the config must exist on the local filesystem

Caution

The STARSHIP_CONFIG environment variable can redirect config loading to any file path. In shared environments (multi-user servers, CI), ensure this variable is not set by untrusted profile scripts. A crafted config could define module format strings or custom command overrides that cause unintended behavior.

7.3 Environment Variable Exposure

Starship reads numerous environment variables for shell detection, terminal identification, and module behavior. In environments where environment variables contain secrets:

  • Starship does not log environment variable values at info level or below
  • At debug and trace levels (STARSHIP_LOG=debug or STARSHIP_LOG=trace), environment state may be written to log files in the cache directory
  • Log files are written to the user's cache directory with standard user permissions
  • The bug-report command collects environment information — review its output before sharing publicly

7.4 Build Supply Chain

Key dependencies for a security audit:

Crate Version Risk Surface
gix 0.81.0 Git protocol parsing, SHA computation
toml / toml_edit 1.1.2 / 0.25.11 Config file parsing
clap 4.6.1 CLI argument parsing
regex 1.12.3 Pattern matching (ReDoS potential on malformed patterns)
serde / serde_json 1.0.228 / 1.0.149 Serialization (no untrusted input in normal use)
nu-ansi-term 0.50.3 ANSI escape sequence generation
os_info 3.14.0 OS detection (reads /etc/os-release etc.)
whoami 2.1.1 Username/hostname detection

All dependencies are Rust crates from crates.io with standard Cargo.lock pinning.

7.5 Platform-Specific Security Notes

Windows: The deelevate crate detects whether the process is running elevated (administrator). The windows crate provides Win32 API access. Neither grants additional privileges beyond what the invoking user already has.

Unix: The nix crate provides POSIX API bindings. Starship does not use setuid, capabilities, or any privilege escalation mechanism.


8. Developer Internals

8.1 Source Layout

src/
├── main.rs                  CLI entry point (clap derive)
├── lib.rs                   Library root, re-exports
├── config.rs                ModuleConfig trait, style parsing, StarshipConfig
├── context.rs               Context struct (shell, env, git, dir scanning)
├── configure.rs             Config editing (update, toggle, print, edit)
├── module.rs                Module struct, ALL_MODULES constant
├── print.rs                 Prompt rendering, explain, timings, presets
├── segment.rs               Segment struct (styled text unit)
├── bug_report.rs            Bug report generation
├── logger.rs                Session-based logging with auto-cleanup
│
├── configs/
│   ├── mod.rs               StarshipRootConfig, PROMPT_ORDER, FullConfig
│   └── *.rs                 Per-module config structs (90+ files)
│
├── modules/
│   ├── mod.rs               handle() dispatch, description()
│   ├── *.rs                 Per-module implementations (90+ files)
│   └── utils/               Directory scanning, path utils, truncation
│
├── formatter/
│   ├── mod.rs               Formatter module entry
│   ├── model.rs             TextGroup, FormatElement, StyleElement
│   ├── parser.rs            PEG parser implementation
│   ├── spec.pest            PEG grammar definition
│   ├── string_formatter.rs  StringFormatter (template engine)
│   └── version.rs           VersionFormatter
│
├── init/
│   ├── mod.rs               Shell init logic, StarshipPath
│   ├── starship.bash
│   ├── starship.fish
│   ├── starship.zsh
│   ├── starship.ps1
│   ├── starship.elv
│   ├── starship.nu
│   ├── starship.lua
│   ├── starship.tcsh
│   └── starship.xsh
│
└── utils/
    ├── mod.rs               exec_cmd, read_file, home_dir
    ├── env.rs               Environment variable handling
    ├── serde.rs             Custom TOML deserialization (ValueDeserializer)
    └── statusline.rs        Statusline utilities

8.2 Key Abstractions

Context (src/context.rs)

The Context struct is the central state object passed to every module. It encapsulates:

  • Detected shell name and properties
  • Environment variable access
  • Current working directory
  • Git repository discovery (via gix)
  • DirContents — cached directory scan results with timeout support
  • Reference to the parsed StarshipConfig

Context is created once per prompt invocation and shared (by reference) across all module calls.

Module (src/module.rs)

The Module struct represents a rendered prompt component:

  • Contains a name and a vector of Segments
  • The ALL_MODULES constant lists every registered module name as a static array
  • The handle() function in src/modules/mod.rs dispatches to the correct module function by name
  • description() returns a human-readable description for each module (used by explain)

Segment (src/segment.rs)

A Segment is the atomic unit of prompt output — a styled text fragment. Each module produces zero or more segments. The print system concatenates all segments from all modules into the final prompt string with appropriate ANSI escape codes.

StringFormatter (src/formatter/string_formatter.rs)

The template engine that processes format strings:

  1. Parses the format string through the PEG grammar (spec.pest)
  2. Produces a tree of FormatElement and TextGroup nodes
  3. Resolves variables by calling registered mappers
  4. Handles conditionals — ($optional) blocks are omitted if any variable resolves to empty
  5. Applies styles from [$text](style) syntax

8.3 Module Development Pattern

To add a new module, four files must be touched:

  1. Config struct — Create src/configs/<module_name>.rs:

    use serde::{Deserialize, Serialize};
    use crate::config::ModuleConfig;
    
    #[derive(Clone, Serialize, Deserialize)]
    #[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]
    #[serde(default)]
    pub struct MyModuleConfig<'a> {
        pub format: &'a str,
        pub symbol: &'a str,
        pub style: &'a str,
        pub disabled: bool,
        pub detect_files: Vec<&'a str>,
        pub detect_extensions: Vec<&'a str>,
        pub detect_folders: Vec<&'a str>,
    }
    
    impl<'a> Default for MyModuleConfig<'a> {
        fn default() -> Self {
            MyModuleConfig {
                format: "via [$symbol($version)]($style) ",
                symbol: "X ",
                style: "bold blue",
                disabled: false,
                detect_files: vec!["my_file"],
                detect_extensions: vec!["myext"],
                detect_folders: vec![],
            }
        }
    }
    
    impl<'a> ModuleConfig<'a> for MyModuleConfig<'a> {}
    
  2. Module implementation — Create src/modules/<module_name>.rs:

    use super::Context;
    use super::Module;
    
    pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
        // 1. Load config
        // 2. Check detection criteria via context.dir_contents()
        // 3. Execute commands if needed via context.exec_cmd()
        // 4. Create StringFormatter, map variables
        // 5. Return Some(module) or None
    }
    
  3. Registration — Add the module to:

    • ALL_MODULES in src/module.rs
    • handle() dispatch match arm in src/modules/mod.rs
    • description() match arm in src/modules/mod.rs
    • PROMPT_ORDER in src/configs/mod.rs (if it should appear in $all)
    • Config re-export in src/configs/mod.rs
  4. Tests — Add tests in the module file or a dedicated test module

8.4 Testing

Test framework: Standard Rust #[test] with:

  • mockall 0.14.0 — mock trait implementations for isolated testing
  • tempfile 3.27.0 — temporary directories for filesystem-dependent tests

Test patterns:

  • Module tests create a temporary directory, populate it with detection files, build a Context, and assert the module output
  • Config tests verify serde defaults and round-trip serialization
  • Formatter tests verify PEG grammar parsing against known format strings

Run all tests:

cargo test

Run tests with a specific feature:

cargo test --features config-schema

8.5 Custom TOML Deserialization

src/utils/serde.rs implements ValueDeserializer — a custom TOML deserialization layer that enables Starship's module config pattern. This allows modules to define strongly-typed config structs with defaults while still accepting arbitrary TOML values from user configuration. The deserializer bridges TOML's dynamic value types to Rust's static type system.

8.6 Directory Scanning

The DirContents utility (src/modules/utils/) scans the current directory for files, extensions, and folder names. Key behavior:

DirContents::from_path_with_timeout(path, timeout)
  • Respects the scan_timeout root config value
  • Results are cached on the Context so multiple modules do not re-scan
  • follow_symlinks config controls whether symbolic links are followed during traversal
  • Scanning provides O(1) lookups for file existence, extension presence, and folder name checks after the initial scan completes

8.7 Git Integration

Starship uses gix 0.81.0 with feature flags max-performance-safe, revision, status, and sha1:

  • Repository discovery: Context locates the git repo by walking up from the current directory
  • Status: git_status module reads modified/staged/untracked/conflicted counts
  • Metrics: git_metrics shares state with git_status via parking_lot to avoid redundant computation
  • Branch/commit: Read from git HEAD reference

The gix integration avoids shelling out to git for most operations, reducing per-prompt latency. External git may still be used for some edge cases not covered by the gix feature set.

8.8 Version Parsing

Version parsing uses two crates for maximum compatibility:

  • semver 1.0.28 — strict SemVer parsing (for tools that produce compliant version strings)
  • versions 7.0.0 — lenient version parsing (handles non-SemVer output like Python 3.12.1, go version go1.22.0 linux/amd64)

This dual approach ensures modules can parse version output from virtually any command-line tool regardless of output format.

8.9 ANSI Terminal Output

Terminal output uses nu-ansi-term 0.50.3 for generating ANSI escape sequences and terminal_size 0.4.4 for detecting terminal dimensions. The rendering pipeline:

  1. Each Segment carries a Style (colors + attributes)
  2. nu-ansi-term converts styles to platform-appropriate ANSI escape codes
  3. Terminal width from terminal_size is passed to modules that need to handle truncation or alignment

9. Integration Points

9.1 Shell Integration Details

Each shell init script in src/init/ follows a consistent pattern:

  1. Capture the starship binary path — StarshipPath resolves the absolute path to avoid $PATH lookups on every prompt
  2. Register hooks — each shell's native hook mechanism (precmd, PROMPT_COMMAND, fish_prompt, etc.)
  3. Pass prompt properties — exit status ($?), command duration, number of background jobs, terminal width, vi-mode keymap
  4. Call starship prompt — the hook invokes starship prompt with the collected properties as command-line arguments
  5. Capture right prompt — shells that support it also call starship prompt --right for right_format

The init_stub and init_main functions in src/init/mod.rs generate the shell-specific code, with the init scripts themselves stored as embedded string resources.

9.2 Git Repository Integration

Starship auto-discovers git repositories by walking up from the current directory. Multiple modules consume git state:

Module Git Data Used
git_branch Current branch or detached HEAD
git_commit Commit hash, tag
git_state Rebase, merge, cherry-pick, bisect state
git_status Modified, staged, untracked, conflicted counts
git_metrics Added/deleted line counts (shares state with git_status)

Note

The git_status and git_metrics modules share a single computation via parking_lot synchronization. Disabling git_status while keeping git_metrics enabled will still trigger the shared git state computation. Disabling both saves the most time in large repositories.

9.3 Language/Tool Detection

Module detection is file-based. Each module defines arrays of filenames, extensions, and folder names to look for in the current directory via DirContents. Representative detection patterns:

Module type Detection Files Detection Extensions Detection Folders
Node.js package.json, .node-version .js, .mjs, .cjs, .ts node_modules
Python requirements.txt, pyproject.toml, setup.py .py
Rust Cargo.toml .rs
Go go.mod, go.sum .go

Detection is performed via the cached DirContents scan, ensuring O(1) lookups after the initial directory scan completes within the scan_timeout window.

9.4 Terminal Detection

Starship detects the terminal emulator via environment variables:

  • TERM_PROGRAM — primary detection (e.g., iTerm.app, WezTerm, vscode)
  • LC_TERMINAL — alternative detection path
  • TERM_PROGRAM_VERSION / LC_TERMINAL_VERSION — terminal version information

This information is used by modules that adapt their output based on terminal capabilities (e.g., symbol rendering, color depth assumptions).

9.5 External Command Execution

The exec_cmd utility (src/utils/mod.rs) provides a standardized interface for modules to run external commands:

  • Commands are executed with the user's environment
  • command_timeout from root config bounds execution time
  • Output is captured (stdout) and returned as a string for the calling module to parse
  • Failed or timed-out commands return None, causing the module to silently produce no output

9.6 Cross-Module State Sharing

The primary instance of cross-module state is the git_status/git_metrics pair:

  • git_status performs the full git status computation
  • Results are stored in a parking_lot-protected shared structure
  • git_metrics reads from this shared state instead of recomputing

This pattern is intentionally limited to this single case. All other modules are fully independent, enabling safe parallel execution via rayon without synchronization overhead.

9.7 Known Issues (from GitHub)

Issue Description Impact
#2057 Slow prompt on PowerShell/Windows Windows users experience higher latency due to PowerShell overhead
#7400 git_status info/exclude not respected in worktrees Git worktree users may see incorrect status
#7094 Status module error display Error codes may not render correctly in edge cases
#7403 Tab completion in su -l Completions may not work after switching users
#6955 macOS install issues Platform-specific installation edge cases
#6763 Catppuccin preset install error Preset application may fail for this preset

Note

These issues reflect the state of the repository at the documented commit. Check the GitHub issue tracker for current status and workarounds.

9.8 Documentation Site

The docs/ directory contains a VitePress-based documentation site with support for 20+ locales. This is a separate build artifact from the Starship binary itself and is deployed to starship.rs. The preset TOML files in docs/public/presets/toml/ serve double duty: they are the source for the documentation site and are embedded into the binary at compile time by build.rs.