beachcomber 0.5.1

A centralized daemon that caches shell state (git, battery, hostname, etc.) so every consumer reads from one fast cache instead of independently forking shells
Documentation
---
sidebar_position: 4
---

# Powerlevel10k

## Introduction

powerlevel10k (p10k) is one of the fastest zsh themes. It uses gitstatus — a purpose-built C++ daemon — for git information, tightly integrated into its async rendering pipeline. beachcomber can replace gitstatus as the git data source, consolidating all shell state queries into a single daemon instead of running two.

beachcomber also provides cached data for things p10k does not cover natively, such as mise project tool versions.

There are two levels of integration:

- **Complementary segments** — add beachcomber-backed segments alongside p10k's built-in ones
- **Full git replacement** — replace gitstatus entirely with a beachcomber-backed segment

## Prerequisites

- beachcomber installed and the daemon running (`comb s` should succeed)
- powerlevel10k installed and configured (`p10k configure` has been run at least once)
- `~/.p10k.zsh` exists (generated by the configuration wizard)

## The durability problem

`~/.p10k.zsh` is regenerated when you run `p10k configure`. Any edits to that file will be overwritten. beachcomber integration must survive regeneration.

The solution is an **overlay file** — a separate zsh script sourced immediately after `~/.p10k.zsh`. It patches the prompt element arrays and defines custom segment functions. When `p10k configure` regenerates `~/.p10k.zsh`, the overlay re-applies its changes on next shell startup. The generated file is never modified.

### Setting up the overlay

Create `~/.config/zsh/beachcomber-p10k.zsh` (or any path you prefer) and source it in your `.zshrc` immediately after the p10k config:

```zsh
# .zshrc
source ~/.p10k.zsh
source ~/.config/zsh/beachcomber-p10k.zsh
```

All beachcomber segment definitions and array patches go in the overlay file. The rest of this guide shows what to put in it.

## Complementary segments

These segments add data that p10k does not provide natively. They work alongside p10k's built-in segments without replacing anything.

### Kubernetes context

```zsh
# comb g returns plain text by default. g = get, no suffix needed.
function prompt_bc_kube() {
    local ctx=$(comb g kubecontext.context 2>/dev/null)
    [[ -n "$ctx" ]] || return
    p10k segment -f cyan -i '☸' -t "$ctx"
}
```

### AWS profile

```zsh
function prompt_bc_aws() {
    local profile=$(comb g aws.profile 2>/dev/null)
    [[ -n "$profile" ]] || return
    p10k segment -f yellow -t "$profile"
}
```

The beachcomber AWS provider detects profiles from both `$AWS_PROFILE` (native CLI, granted) and `$AWS_VAULT` (aws-vault), with session expiration tracking via `$AWS_CREDENTIAL_EXPIRATION`.

### GCloud project

```zsh
function prompt_bc_gcloud() {
    local project=$(comb g gcloud.project 2>/dev/null)
    [[ -n "$project" ]] || return
    p10k segment -f blue -t "$project"
}
```

### mise project tools

Shows tool versions that are overridden at the project level (from a local `mise.toml`), distinguishing them from the global baseline. Only appears in directories with a project-level mise config.

```zsh
typeset -g POWERLEVEL9K_COMB_MISE_FOREGROUND=147
typeset -g POWERLEVEL9K_COMB_MISE_VISUAL_IDENTIFIER_EXPANSION=$'\uF07C'  # folder-open icon

function prompt_comb_mise() {
  local cwd=${(%):-%/}
  local project
  project=$(comb g mise.project "$cwd" 2>/dev/null) || return
  [[ -z "$project" ]] && return

  local display=()
  local entry tool ver
  for entry in "${(@s:,:)project}"; do
    [[ -z "$entry" ]] && continue
    tool=${entry%%=*}
    ver=${entry#*=}
    display+=("${tool} ${ver}")
  done
  p10k segment -f 147 -i $'\uF07C' -t "${(j: | :)display}"
}
```

The beachcomber mise provider exposes three fields:

- `mise.project` — only tools sourced from a local `mise.toml` (project-scoped overrides)
- `mise.global` — only tools sourced from `~/.config/mise/` (the global baseline)
- `mise.tools` — all tools combined with `P:` and `G:` prefixes

### Adding complementary segments to the prompt

After defining the functions, patch the elements array in the overlay. This example inserts `comb_mise` before the `time` segment:

```zsh
typeset -ga _comb_rpe=()
for _comb_e in "${POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS[@]}"; do
  [[ "$_comb_e" == "time" ]] && _comb_rpe+=(comb_mise)
  _comb_rpe+=("$_comb_e")
done
POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=("${_comb_rpe[@]}")
unset _comb_rpe _comb_e
```

For simpler cases, append to the end:

```zsh
POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS+=(bc_kube bc_aws bc_gcloud)
```

## Full git replacement

This replaces p10k's gitstatus-backed `vcs` segment with a custom `comb_git` segment that reads all git state from beachcomber. When `vcs` is removed from the elements array, p10k does not start the gitstatus daemon — eliminating one long-running process from your system.

### Why replace gitstatus?

gitstatus is already fast. The motivation is architectural, not performance:

- **One daemon instead of two.** gitstatus runs one C++ daemon per shell session. beachcomber runs one daemon shared across all shells, tmux panes, and other consumers. Fewer processes, less memory, shared cache.
- **Consistent data.** The same git state that feeds your prompt also feeds your tmux status bar, neovim statusline, and any other beachcomber consumer. No divergence between tools.
- **Broader coverage.** beachcomber's git provider includes fields that gitstatus does not expose, such as line-level diff stats (`lines_added`, `lines_removed`), stash counts, and the current tag.

### Current limitations

beachcomber's git provider now exposes `commit_summary` (the first line of the HEAD commit message) and `push_ahead`/`push_behind` (commits ahead of or behind the push remote). The `comb_git` segment above can be extended to use these fields. WIP detection and push indicator rendering require wiring them into the segment function — see the field table in [Built-in Providers](../reference/built-in-providers.md) for the field names.

### The comb_git segment

Add this to your overlay file:

```zsh
# Swap vcs for comb_git in the left prompt elements.
POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(${POWERLEVEL9K_LEFT_PROMPT_ELEMENTS[@]/vcs/comb_git})

# Colours matching the default vcs segment config
typeset -g POWERLEVEL9K_COMB_GIT_CLEAN_FOREGROUND=76
typeset -g POWERLEVEL9K_COMB_GIT_MODIFIED_FOREGROUND=178
typeset -g POWERLEVEL9K_COMB_GIT_UNTRACKED_FOREGROUND=76
typeset -g POWERLEVEL9K_COMB_GIT_VISUAL_IDENTIFIER_EXPANSION=
typeset -g POWERLEVEL9K_COMB_GIT_LOADING_VISUAL_IDENTIFIER_COLOR=244

function prompt_comb_git() {
  local cwd=${(%):-%/}
  local output
  output=$(comb g git "$cwd" 2>/dev/null) || return
  [[ -z "$output" ]] && return

  # Parse key=value lines into an associative array
  local -A g
  local line
  for line in ${(f)output}; do
    local key=${line%%=*}
    local val=${line#*=}
    g[$key]=$val
  done

  [[ -z ${g[branch]} ]] && [[ -z ${g[commit]} ]] && return

  # Determine state for foreground colour
  local state=CLEAN
  if (( ${g[unstaged]:-0} || ${g[conflicted]:-0} || ${g[staged]:-0} )); then
    state=MODIFIED
  elif (( ${g[untracked]:-0} )); then
    state=UNTRACKED
  fi

  # Build display string matching p10k's default git formatting
  local meta='%f'
  local clean='%76F'
  local modified='%178F'
  local untracked='%39F'
  local conflicted='%196F'

  local res

  # Branch name (truncate if > 32 chars)
  if [[ -n ${g[branch]} ]]; then
    local branch=${g[branch]}
    (( $#branch > 32 )) && branch="${branch[1,12]}…${branch[-12,-1]}"
    res+="${clean}${branch//\%/%%}"
  elif [[ -n ${g[tag]} && ${g[tag]} != "null" ]]; then
    local tag=${g[tag]}
    (( $#tag > 32 )) && tag="${tag[1,12]}…${tag[-12,-1]}"
    res+="${meta}#${clean}${tag//\%/%%}"
  elif [[ -n ${g[commit]} ]]; then
    res+="${meta}@${clean}${g[commit][1,8]}"
  fi

  # Upstream tracking branch (only if different from local)
  if [[ -n ${g[upstream]} && ${g[upstream]} != "null" ]]; then
    local remote_branch=${g[upstream]#*/}
    if [[ -n ${remote_branch} && ${remote_branch} != ${g[branch]} ]]; then
      res+="${meta}:${clean}${remote_branch//\%/%%}"
    fi
  fi

  # Ahead/behind
  if (( ${g[ahead]:-0} || ${g[behind]:-0} )); then
    (( ${g[behind]:-0} )) && res+=" ${clean}⇣${g[behind]}"
    (( ${g[ahead]:-0} && !${g[behind]:-0} )) && res+=" "
    (( ${g[ahead]:-0} )) && res+="${clean}⇡${g[ahead]}"
  fi

  # Stashes
  (( ${g[stash]:-0} )) && res+=" ${clean}*${g[stash]}"
  # Merge/rebase state
  [[ ${g[state]} != "clean" && -n ${g[state]} ]] && res+=" ${conflicted}${g[state]}"
  # Conflicted
  (( ${g[conflicted]:-0} )) && res+=" ${conflicted}~${g[conflicted]}"
  # Staged
  (( ${g[staged]:-0} )) && res+=" ${modified}+${g[staged]}"
  # Unstaged
  (( ${g[unstaged]:-0} )) && res+=" ${modified}!${g[unstaged]}"
  # Untracked
  (( ${g[untracked]:-0} )) && res+=" ${untracked}?${g[untracked]}"

  p10k segment -s $state -t "$res"
}
```

The element substitution `${POWERLEVEL9K_LEFT_PROMPT_ELEMENTS[@]/vcs/comb_git}` replaces `vcs` with `comb_git` in whatever array `~/.p10k.zsh` defined. If `p10k configure` regenerates the file with `vcs` back in the array, the overlay swaps it out again on next shell startup.

### Verifying gitstatus is not running

After opening a new shell with the overlay active, confirm gitstatus is stopped:

```sh
pgrep -P $$ gitstatusd
```

This should return nothing. If it returns a PID, the `vcs` segment is still in the elements array — check that the overlay is being sourced after `~/.p10k.zsh`.

### First-prompt cache miss

On the very first prompt after the daemon starts (or after switching to a new directory that has not been queried before), the git provider executes inline. The `comb g` call blocks briefly while the provider runs and returns the result directly — the segment will have data on that first prompt, with a short delay while git runs. Subsequent prompts return the cached value with no delay.

Once the provider has run for a given directory, the cache is kept warm by ongoing demand from prompt queries.

## Customizing colours

All beachcomber segments follow p10k's standard colour configuration. For a segment named `comb_git`, set:

```zsh
typeset -g POWERLEVEL9K_COMB_GIT_FOREGROUND=76
typeset -g POWERLEVEL9K_COMB_GIT_CLEAN_FOREGROUND=76
typeset -g POWERLEVEL9K_COMB_GIT_MODIFIED_FOREGROUND=178
```

The `-s $state` argument in `p10k segment` selects which colour variant to use. States map to the `_CLEAN_`, `_MODIFIED_`, and `_UNTRACKED_` colour keys.

## Reverting

To revert all beachcomber integration:

1. Comment out or delete the `source` line for the overlay in `.zshrc`
2. Restart zsh

The `~/.p10k.zsh` file was never modified. The `vcs` segment will reappear and gitstatus will start again automatically.

To revert just the git replacement while keeping other segments, remove the `POWERLEVEL9K_LEFT_PROMPT_ELEMENTS` substitution line from the overlay. The `vcs` segment from `~/.p10k.zsh` will take effect again.

## Troubleshooting

- **Segment not showing:** verify the function name exactly matches `prompt_<segment_name>` and the segment name is in the `PROMPT_ELEMENTS` array. Run `echo $POWERLEVEL9K_LEFT_PROMPT_ELEMENTS` to check. A typo in either causes p10k to silently skip it.
- **Git segment slow on first prompt:** on a cold cache the provider executes inline, which takes as long as a normal `git` invocation (typically a few milliseconds). This is a one-time cost per directory.
- **Overlay not taking effect:** ensure the `source` line comes after the `~/.p10k.zsh` source in `.zshrc`. The overlay must run second to patch the arrays.
- **gitstatus still running:** check `pgrep -P $$ gitstatusd`. If it returns a PID, `vcs` is still in the elements array. The overlay may not be loaded — check `type prompt_comb_git` to see if the function exists.
- **Icons not rendering:** the Nerd Font glyphs require a patched font. p10k's recommended fonts include all required glyphs. Replace icons with text labels if your font lacks them.
- **Changes lost after `p10k configure`:** this is expected — `p10k configure` regenerates `~/.p10k.zsh`. The overlay re-applies changes on next shell startup. Just open a new shell.

See the [Troubleshooting](./troubleshooting.md) guide for general diagnostics.