noshdocs

Plugins

Extend nosh with custom prompt variables

Plugins

Plugins add dynamic variables to your prompt. They can show git info, execution time, language versions, or anything you can get from a shell command.

How Plugins Work

Plugins are TOML files that define:

  1. Variables - Named values that can be used in themes
  2. Commands - Shell commands to get the values
  3. Transforms - How to process the output

When your prompt renders, nosh fetches all plugin values in parallel with smart timeout handling:

  • Parallel execution - All plugin commands run concurrently, not one after another
  • Soft timeout (100ms) - If a command doesn't finish in time, nosh uses the cached value and keeps running the command in the background
  • Background continuation - Slow commands keep running after the prompt appears, updating the cache for next time
  • Hard timeout (5s) - Commands that take too long are eventually terminated
  • No duplicate runs - If a plugin is still running from the previous prompt, nosh won't start it again

This means your prompt stays fast even with slow plugins. The first time you enter a directory, a slow plugin might show nothing (empty cache), but by the next prompt it will have the value ready.

Built-in Plugins

nosh comes with three plugins in packages/builtins/plugins/:

builtins/context

The most useful plugin. It detects your project context without running slow shell commands:

  • Git info: branch name, dirty status
  • Language versions: Rust, Node.js, Python, Go, Bun, Docker
  • Package info: name and version from package.json, Cargo.toml, etc.
# In your theme
format = "[{builtins/context:git_branch}](purple) [{builtins/context:rust_version}](red)"

[plugins]
"builtins/context" = { enabled = true }

All context variables:

VariableWhat it shows
git_branchCurrent branch name
git_status* if uncommitted changes
rust_versionRust toolchain (e.g., 1.75.0)
rust_icon🦀 when in a Rust project
node_versionNode.js version
node_icon⬢ when in a Node project
python_versionPython version
python_icon🐍 when in a Python project
go_versionGo version
go_icon🐹 when in a Go project
bun_versionBun version
bun_icon🥟 when in a Bun project
docker_versionDocker version
docker_icon🐳 when Docker is available
package_namePackage name from manifest
package_versionPackage version
package_icon📦 when in a package

builtins/exec_time

Shows how long commands take to run:

format = "[{builtins/exec_time:took}](yellow)"

[plugins]
"builtins/exec_time" = { enabled = true, min_ms = 500 }

The min_ms option hides the time for fast commands. Set it to 500 to only show for commands taking over half a second.

VariableExample
tooktook 2.3s
duration2.3s

builtins/git

Git info via shell commands (alternative to context plugin):

format = "[{builtins/git:branch}](purple){builtins/git:dirty}"
VariableDescription
branchCurrent branch name
dirtyShows * if there are changes

Creating Your Own Plugin

Step 1: Create the file

Run /create and select "Plugin", or create manually:

~/.config/nosh/packages/local/plugins/myplugin.toml

Step 2: Write the plugin

Here's a simple example that shows the current time:

[plugin]
name = "clock"
description = "Current time"

[provides]
time = { command = "date +%H:%M" }

Step 3: Use it in your theme

format = "[{local/clock:time}](cyan) [{dir}](blue) $ "

Plugin Format Reference

Basic structure

[plugin]
name = "myplugin"           # Required: unique identifier
description = "Description" # Optional: what it does

[provides]
# Define your variables here

[icons]
# Icons for transforms (optional)

[config]
# Plugin-specific settings (optional)

Command-based variables

Run a shell command and use the output:

[provides]
# Simple command
branch = { command = "git branch --show-current 2>/dev/null" }

# Command with error suppression
uptime = { command = "uptime | awk '{print $3}' 2>/dev/null" }

Transform-based variables

Process the command output:

[provides]
dirty = { command = "git status --porcelain", transform = "non_empty" }

[icons]
dirty = "*"    # Shown when command has output
clean = ""     # Shown when command output is empty

Available transforms:

TransformWhat it does
non_emptyReturns icon based on whether there's output (uses dirty/clean icons)
with_iconPrepends the variable's icon when value exists; hides entirely if empty
trimRemoves leading/trailing whitespace

Using with_icon:

[provides]
temp = { command = "curl -s 'wttr.in?format=%t'", transform = "with_icon" }

[icons]
temp = "🌡️"   # Icon name must match variable name

When the command returns +5°C, the output is 🌡️ +5°C. When empty or timed out, nothing is shown.

Timeout and Cache Settings

Control how long nosh waits for a command and how long results are cached:

[provides]
# Fast command - wait up to 50ms, cache for 1 second
fast_var = { command = "echo hello", timeout = "50ms", cache = "1s" }

# Slow API - don't wait at all (fully async), cache for 5 minutes
weather = { command = "curl -s 'wttr.in?format=%t'", timeout = "0", cache = "5m" }

# Volatile data - always fetch fresh (no caching)
time = { command = "date +%H:%M:%S", cache = "always" }

# Static data - cache forever (only fetch once)
hostname = { command = "hostname", cache = "never" }

Timeout values:

ValueWhat happens
"0"Fully async - show cached value immediately, fetch in background
"100ms"Wait up to 100ms for result (default)
"1s"Wait up to 1 second

Cache values:

ValueWhat happens
"always"Always fetch fresh - no caching
"never"Cache forever - only fetch once per session
"500ms"Cache for 500 milliseconds (default)
"10s"Cache for 10 seconds
"5m"Cache for 5 minutes
"1h"Cache for 1 hour

Use timeout = "0" with cache = "5m" for slow API calls like weather - the first prompt won't show the value, but subsequent prompts will use the cached result while fetching updates in the background.

Internal variables

Use nosh's built-in providers (faster than shell commands):

[provides]
git_branch = { source = "internal" }

Example Plugins

Weather

[plugin]
name = "weather"
description = "Current weather from wttr.in"

[provides]
temp = { command = "curl -s 'wttr.in?format=%t' 2>/dev/null", transform = "with_icon" }
condition = { command = "curl -s 'wttr.in?format=%C' 2>/dev/null" }

[icons]
temp = "🌡️"

Use with_icon to show 🌡️ +5°C when available, or nothing when the API times out.

Battery (macOS)

[plugin]
name = "battery"
description = "Battery percentage"

[provides]
percent = { command = "pmset -g batt | grep -o '[0-9]*%' | head -1" }
charging = { command = "pmset -g batt | grep -q 'AC Power' && echo '⚡' || echo ''" }

Kubernetes Context

[plugin]
name = "k8s"
description = "Kubernetes context and namespace"

[provides]
context = { command = "kubectl config current-context 2>/dev/null" }
namespace = { command = "kubectl config view --minify -o jsonpath='{..namespace}' 2>/dev/null" }

Docker Containers

[plugin]
name = "docker"
description = "Running Docker containers"

[provides]
count = { command = "docker ps -q 2>/dev/null | wc -l | tr -d ' '" }
running = { command = "docker ps --format '{{.Names}}' 2>/dev/null | head -1" }

Plugin Naming

How you reference a plugin depends on where it's from:

SourceLocationUsage in theme
Built-inpackages/builtins/plugins/{builtins/plugin:var}
Your ownpackages/local/plugins/{local/plugin:var}
Packagepackages/name/plugins/{name/plugin:var}

Enabling Plugins in Themes

Every plugin you use must be enabled in your theme:

[plugins]
"builtins/context" = { enabled = true }
"builtins/exec_time" = { enabled = true, min_ms = 1000 }
"weather" = { enabled = true }
"k8s" = { enabled = false }  # Disabled

Performance Tips

  1. Use builtins/context instead of shell commands - It's much faster because it doesn't spawn processes. Context variables are computed synchronously and never delay your prompt.

  2. Use timeout = "0" for slow commands - API calls or slow commands should use timeout = "0" to avoid delaying your prompt. The first time shows nothing, but subsequent prompts show cached values while fetching in the background.

  3. Cache aggressively for stable data - Use cache = "5m" or cache = "never" for data that doesn't change often (weather, hostname, k8s context). This reduces unnecessary command execution.

  4. Use cache = "always" sparingly - Only for truly volatile data that must be fresh every prompt. This causes a command to run on every prompt.

  5. Keep commands under 100ms when possible - Faster commands mean immediately visible data instead of cached values. Use 2>/dev/null to suppress error output and speed up failing commands.

  6. Disable plugins you don't use - Set enabled = false to skip them entirely.

  7. Background execution limits - If a command takes more than 5 seconds, it's killed to prevent resource buildup. Design your plugins to complete within a reasonable time.

Installing Plugin Packages

Get plugins made by others:

/install user/repo          # Install from GitHub
/sync                       # Update all packages
/packages                   # Manage packages

Then enable in your theme:

[plugins]
"repo-name/plugin-name" = { enabled = true }