dotfiles

A collection of literate programming dotfiles created and maintained in Emacs with Org mode. The source is available at index.org.1

Table of Contents

Build Configuration Files

CUSTOM_ID: build-configuration-files

Open this Org document in Emacs and tangle it (C-c C-v t). Configuration files, e.g., ~/.bashrc, will be generated.

Bootstrap

CUSTOM_ID: bootstrap

Change Default Shell

CUSTOM_ID: change-default-shell

I prefer bash over zsh.

This should be the Homebrew installed bash not the system bash path:

eval "$(/opt/homebrew/bin/brew shellenv)" && \
    export SHELL="${HOMEBREW_PREFIX}/bin/bash" && \
    sudo dscl . -create ${HOME} UserShell ${SHELL} && \
    dscl . -read ${HOME} UserShell

Set HOSTNAME

CUSTOM_ID: set-hostname
export HOSTNAME='TODO' && \
    sudo scutil --set HostName ${HOSTNAME}

Accessibility

CUSTOM_ID: accessibility
defaults write com.apple.Accessibility ReduceMotionEnabled -bool true

Bash

CUSTOM_ID: bash

~/.bash_profile

CUSTOM_ID: bash-profile
header-args: :mkdirp yes :tangle ~/.bash_profile
# shellcheck source=/dev/null
source "${HOME}/.bashrc"

~/.bashrc

CUSTOM_ID: bashrc
header-args: :mkdirp yes :tangle ~/.bashrc

Load all configuration:

export K20E_BASHRC_DIR="${HOME}/.bashrc.d"
for f in "${K20E_BASHRC_DIR}/"*.bash; do
    # shellcheck source=/dev/null
    source "${f}"
done
unset -v f

Configuration

CUSTOM_ID: configuration
header-args: :mkdirp yes :tangle ~/.bashrc.d/000-bash.bash

Environment variables:

export LANG=en_US.UTF-8

export HISTSIZE=100000
export HISTCONTROL=ignoredups:erasedups
export HISTTIMEFORMAT='%F %T '

export TERM=xterm-256color

Shell options:

shopt -s \
      autocd \
      cdspell \
      checkjobs \
      checkwinsize \
      dirspell \
      histappend \
      no_empty_cmd_completion

Base variables that I use to organize the file system:

export K20E_CODE_HOME=${HOME}/code
export GOOGLE="${HOME}/Google Drive/My Drive"

CDPATH:

The CDPATH variable sets the search path for the cd command. If you do not specify . somewhere in the path, it is assumed to be the first component.

export CDPATH="${K20E_CODE_HOME}:${GOOGLE}"

PATH:

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}
pathmunge /usr/local/sbin
pathmunge /usr/local/bin
pathmunge "${HOME}/.local/bin"
pathmunge "${HOME}/bin"

TODO If these modify PATH, etc., I should figure out a way to pre/post them with the rest of this setup.

Aliases:

alias ..="cd ../"
alias ...="cd ../../"
alias ....="cd ../../.."
alias dirs="dirs -v"
function k20e_cd_root() {
    local root
    root="$(jj root 2>/dev/null || git rev-parse --show-toplevel 2>/dev/null)" && [ -n "$root" ] && [ "${PWD}" != "$root" ] && { cd "$root" || return; }
}
alias r=k20e_cd_root
alias tree="tree -C"
alias top="top -ocpu -Orsize"

Homebrew

CUSTOM_ID: homebrew
header-args: :mkdirp yes :tangle ~/.bashrc.d/010-brew.bash
if [ -e /opt/homebrew/bin/brew ]; then
    eval "$(/opt/homebrew/bin/brew shellenv)"

    export HOMEBREW_CASK_HOME="${HOMEBREW_PREFIX}/Caskroom"
    export HOMEBREW_CASK_OPTS=--require-sha
    export HOMEBREW_INSTALL_CLEANUP=1
    export HOMEBREW_NO_ANALYTICS=1
    export HOMEBREW_NO_ASK=1
    export HOMEBREW_NO_ENV_HINTS=1
    export HOMEBREW_NO_INSECURE_REDIRECT=1

    command -v "${HOMEBREW_PREFIX}/bin/bash" >/dev/null 2>&1 && export SHELL="${HOMEBREW_PREFIX}/bin/bash"
fi

Completion:

# shellcheck source=/dev/null
[ -e "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" ] && source "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh"

Homebrew Bundle

CUSTOM_ID: homebrew-bundle

Install: brew bundle

if command -v brew >/dev/null 2>&1; then
    export HOMEBREW_BREWFILE="${HOME}/.Brewfile"

    alias k20e_brew_bundle_dump='brew bundle dump --force --global --verbose && pbcopy < $HOMEBREW_BREWFILE'
    alias k20e_brew_bundle_install="brew bundle --global"
fi

~/.Brewfile

CUSTOM_ID: brewfile
header-args: :mkdirp yes :tangle ~/.Brewfile
tap "buo/cask-upgrade"
tap "d12frosted/emacs-plus"
tap "homebrew/autoupdate"
tap "homebrew/command-not-found"
tap "homebrew/test-bot"
tap "tidbyt/tidbyt"
brew "git"
brew "glow"
brew "aspell"
brew "automake"
brew "bash"
brew "bash-completion@2"
brew "oniguruma"
brew "bat"
brew "bison"
brew "carapace"
brew "chafa"
brew "cmake"
brew "dasel"
brew "diff-so-fancy"
brew "difftastic"
brew "dive"
brew "eza"
brew "fd"
brew "libssh"
brew "xvid"
brew "ffmpeg"
brew "flex"
brew "flyctl"
brew "gawk"
brew "gcc"
brew "gd"
brew "gflags"
brew "gh"
brew "gnupg"
brew "go"
brew "gprof2dot"
brew "hunspell"
brew "shared-mime-info"
brew "imagemagick"
brew "innoextract"
brew "ispell"
brew "jj"
brew "jq"
brew "just"
brew "kubernetes-cli"
brew "kubectx"
brew "less"
brew "libdvdcss"
brew "libyaml"
brew "makedepend"
brew "node"
brew "opam"
brew "parallel"
brew "perl"
brew "pkgconf"
brew "pre-commit"
brew "pstree"
brew "pv"
brew "repo"
brew "ripgrep"
brew "rocksdb"
brew "ruby", link: true
brew "rust"
brew "scons"
brew "sevenzip"
brew "shellcheck"
brew "starship"
brew "subversion"
brew "television"
brew "texi2html"
brew "tree"
brew "uv"
brew "watch"
brew "wget"
brew "yamllint"
brew "yasm"
brew "yq"
brew "yt-dlp"
brew "d12frosted/emacs-plus/emacs-plus@30"
brew "tidbyt/tidbyt/pixlet"
cask "1password"
cask "1password-cli"
cask "alfred"
cask "alt-tab"
cask "betterdisplay"
cask "firefox"
cask "font-symbols-only-nerd-font"
cask "ghostty"
cask "google-chrome"
cask "google-drive"
cask "gzdoom"
cask "heroic"
cask "istat-menus"
cask "lm-studio"
cask "mactex-no-gui"
cask "openusage"
cask "orion"
cask "qlmarkdown"
cask "rancher"
cask "rectangle"
cask "signal"
cask "slack"
cask "tomatobar"
cask "vanilla"
cask "vlc"
cask "whisky"
cask "zed"
cask "zoom"

Secrets

CUSTOM_ID: secrets
header-args: :mkdirp yes :tangle ~/.bashrc.d/011-secrets.bash

Define a directory to keep secret information in. Make sure that it exists in .gitignore-global.

export K20E_SECRET_HOME="${K20E_BASHRC_DIR}/secret"
mkdir -p "${K20E_SECRET_HOME}"

Setup environment and source secrets:

export K20E_SECRET_ENV="${K20E_SECRET_HOME}/secrets.env"
touch -a "${K20E_SECRET_ENV}"

if [ -f "${K20E_SECRET_ENV}" ]; then
    set -a
    # shellcheck source=/dev/null
    source "${K20E_SECRET_ENV}"
    set +a
fi

Adjust permissions.

chmod 0700 "${K20E_SECRET_HOME}"
[ -f "${K20E_SECRET_ENV}" ] && chmod 0600 "${K20E_SECRET_ENV}"

1Password

CUSTOM_ID: 1password
header-args: :mkdirp yes :tangle ~/.bashrc.d/501-1password.bash

Generate completion script:

op completion bash > /opt/homebrew/etc/bash_completion.d/op

# shellcheck source=/dev/null
[ -e "${HOMEBREW_PREFIX}/etc/bash_completion.d/op" ] && source "${HOMEBREW_PREFIX}/etc/bash_completion.d/op"

AWS CLI

CUSTOM_ID: aws-cli
header-args: :mkdirp yes :tangle ~/.bashrc.d/440-awscli.bash
export AWS_SDK_LOAD_CONFIG=1
export AWS_VAULT_KEYCHAIN_NAME=login

[ -e "${HOMEBREW_PREFIX}/bin/aws_completer" ] && complete -C "${HOMEBREW_PREFIX}/bin/aws_completer" aws
[ -e '/usr/bin/aws_completer' ] && complete -C '/usr/bin/aws_completer' aws

bat

CUSTOM_ID: bat
header-args: :mkdirp yes :tangle ~/.bashrc.d/108-bat.bash
if [ -x "${HOMEBREW_PREFIX}/bin/bat" ]; then
    alias cat='bat --theme auto:system --theme-dark default --theme-light GitHub'
    alias less='bat --theme auto:system --theme-dark default --theme-light GitHub'
fi

~/.config/bat

CUSTOM_ID: config-bat
header-args: :mkdirp yes :tangle ~/.config/bat/config
# This is `bat`s configuration file. Each line either contains a comment or
# a command-line option that you want to pass to `bat` by default. You can
# run `bat --help` to get a list of all possible configuration options.

# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes`
# for a list of all available themes
#--theme="TwoDark"

# Enable this to use italic text on the terminal. This is not supported on all
# terminal emulators (like tmux, by default):
#--italic-text=always

# Uncomment the following line to disable automatic paging:
#--paging=never

# Uncomment the following line if you are using less version >= 551 and want to
# enable mouse scrolling support in `bat` when running inside tmux. This might
# disable text selection, unless you press shift.
#--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse"

# Syntax mappings: map a certain filename pattern to a language.
#   Example 1: use the C++ syntax for Arduino .ino files
#   Example 2: Use ".gitignore"-style highlighting for ".ignore" files
#--map-syntax "*.ino:C++"
#--map-syntax ".ignore:Git Ignore"
--plain

Carapace

CUSTOM_ID: carapace
header-args: :mkdirp yes :tangle ~/.bashrc.d/990-carapace.bash

https://carapace.sh/ for Bash and Nushell both.

if command -v carapace >/dev/null 2>&1; then
    export CARAPACE_BRIDGES='zsh,fish,bash'
    # shellcheck disable=SC1090
    source <(carapace _carapace bash)

    # Bridge common aliases to their underlying carapace completer
    _carapace_alias_completer() {
        local alias_name="${COMP_WORDS[0]}"
        local target=""
        case "$alias_name" in
            g) target="git" ;;
            j) target="jj" ;;
            k) target="kubectl" ;;
            c) target="claude" ;;
        esac
        if [[ -n "$target" ]]; then
            COMP_WORDS[0]="$target"
            local prefix="${COMP_LINE:0:${#alias_name}}"
            if [[ "$prefix" == "$alias_name" ]]; then
                COMP_LINE="${target}${COMP_LINE:${#alias_name}}"
                ((COMP_POINT += ${#target} - ${#alias_name}))
            fi
        fi
        _carapace_completer "$@"
    }
    complete -o default -o bashdefault -F _carapace_alias_completer g j k c 2>/dev/null || true
fi

Claude

CUSTOM_ID: claude
header-args: :mkdirp yes :tangle ~/.bashrc.d/111-claude.bash
alias c='claude'

To route Claude Code through OpenRouter on personal machines without polluting the ambient environment or interfering with enterprise credentials on work machines, use OpenRouter's official ori harness: ori claude.

Difftastic

CUSTOM_ID: difftastic
header-args: :mkdirp yes :tangle ~/.bashrc.d/112-difftastic.bash

difft has no configuration file; its defaults are set through DFT_* environment variables (see difft --help). Explicit flags win over these, which lets callers that want something else override them, e.g. Git passes --display=inline.

Setting the display mode here, rather than in Jujutsu's ui.diff-formatter argv, lets jj use its built-in merge-tools.difft invocation unmodified. That invocation passes --width=$width, which difft needs because its output is piped to a pager and it therefore cannot detect the terminal width on its own (it falls back to 80 columns).

export DFT_DISPLAY=side-by-side-show-both

The Nushell equivalent lives in config.nu.

eca

CUSTOM_ID: eca
header-args: :mkdirp yes :tangle ~/.config/eca/config.json

ECA (Editor Code Assistant) configuration.

{
  "$schema": "https://eca.dev/config.json",
  "chat": {
    "defaultTrust": true
  },
  "extraConfigs": ["~/.config/eca/config.local.json", ".eca/config.local.json"],
  "defaultModel": "openrouter/openrouter/auto-beta",
  "providers": {
    "openrouter": {
      "api": "openai-chat",
      "url": "https://openrouter.ai/api/v1",
      "key": "${env:OPENROUTER_API_KEY}",
      "models": {
        "openrouter/auto-beta": {
          "extraPayload": {
            "provider": {
              "data_collection": "deny"
            }
          }
        },
        "openrouter/pareto-code": {
          "extraPayload": {
            "provider": {
              "data_collection": "deny"
            }
          }
        }
      }
    }
  }
}

Emacs

CUSTOM_ID: emacs
header-args: :mkdirp yes :tangle ~/.bashrc.d/107-emacs.bash
[ -x "${HOMEBREW_PREFIX}/bin/emacs" ] && alias emacs='$HOMEBREW_PREFIX/bin/emacs --no-window-system'
[ -x "${HOMEBREW_PREFIX}/bin/emacsclient" ] && alias emacsclient='$HOMEBREW_PREFIX/bin/emacsclient --no-wait'

export EDITOR=emacsclient
export VISUAL=emacsclient

This is a clever emacsclient hack to support opening files at a line number with the :linum suffix that I stumbled across at https://stuff-things.net/2019/07/31/opening-files-with-line-numbers-in-emacs.

function k20e_ec () {
    if [[ $1 =~ (.*):([0-9]+):(.*)$ ]]; then
        emacsclient "+${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}"
    else
        emacsclient "$@"
    fi
}

alias ec=k20e_ec

eza

CUSTOM_ID: eza
header-args: :mkdirp yes :tangle ~/.bashrc.d/130-eza.bash
if command -v eza >/dev/null 2>&1; then
    # Workaround for https://github.com/orgs/eza-community/discussions/209#discussioncomment-10801021 which is apparently still not resolved
    export EXA_COLORS="xx=''"
    export EZA_CONFIG_DIR="${HOME}/.config/eza"
    export EZA_ICON_SPACING=2
    export EZA_ICONS_AUTO=1
    alias l="eza --classify --git --git-repos --grid"
    alias ls="eza --classify --git --git-repos --grid"
    alias ll="eza --classify --git --git-repos --long --header --smart-group"
    alias lt="eza --classify --git --git-repos --tree"
    alias ltl="eza --classify --git --git-repos --tree --long --header --smart-group"
fi

Theme

CUSTOM_ID: theme
header-args: :mkdirp yes :tangle ~/.config/eza/theme.yml

See https://github.com/eza-community/eza-themes

---

Gemini CLI

CUSTOM_ID: gemini-cli

GEMINI.md

CUSTOM_ID: gemini-md
header-args: :mkdirp yes :tangle ~/.gemini/GEMINI.md
---
- The user uses `jj` (Jujutsu) for version control, not `git`.

settings.json

CUSTOM_ID: settings-json
header-args: :mkdirp yes :tangle ~/.gemini/settings.json
{
  "security": {
    "auth": {
      "selectedType": "gemini-api-key"
    },
    "disableYoloMode": true
  },
  "output": {
    "format": "text"
  },
  "ui": {
    "autoThemeSwitching": true,
    "hideTips": true,
    "hideBanner": true,
    "footer": {
      "hideContextPercentage": false,
      "hideSandboxStatus": true
    },
    "loadingPhrases": "off",
    "showLineNumbers": false,
    "showMemoryUsage": true,
    "showModelInfoInChat": true,
    "showStatusInTitle": true,
    "useBackgroundColor": false
  },
  "tools": {
    "shell": {
      "showColor": true
    }
  },
  "general": {
    "checkpoint": {
      "enabled": true
    },
    "previewFeatures": true,
    "preferredEditor": "emacsclient",
    "sessionRetention": {
      "warningAcknowledged": true,
      "enabled": true,
      "maxAge": "30d"
    }
  },
  "mcpServers": {
    "github": {
      "httpUrl": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_TOKEN}",
        "X-MCP-Tools": "add_comment_to_pending_review,get_file_contents,pull_request_read,pull_request_review_write"
      },
      "timeout": 5000
    },
    "google-developer-knowledge": {
      "httpUrl": "https://developerknowledge.googleapis.com/mcp",
      "headers": {
        "X-Goog-Api-Key": "${GOOGLE_DEV_KNOWLEDGE_API_KEY}"
      }
    }
  },
  "model": {
    "compressionThreshold": 0.7
  },
  "privacy": {
    "usageStatisticsEnabled": false
  }
}

Ghostty

CUSTOM_ID: ghostty
header-args: :mkdirp yes :tangle ~/.config/ghostty/config
# See https://github.com/ghostty-org/ghostty/discussions/3501#discussioncomment-12102205
font-codepoint-map = U+E000-U+E00A,U+E0A0-U+E0A3,U+E0B0-U+E0C8,U+E0CA,U+E0CC-U+E0D7,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E6B7,U+E700-U+E8EF,U+EA60-U+EC1E,U+ED00-U+F2FF,U+EE00-U+EE0B,U+F300-U+F381,U+F400-U+F533,U+F0001-U+F1AF0=Symbols Nerd Font

adjust-cell-height = 10%
alpha-blending = native

background-opacity = 0.80
background-blur-radius = 20

# See also shell-integration-features
cursor-style = block
cursor-style-blink = true
cursor-click-to-move = true

font-family = ""
font-family = PragmataPro VF Mono Liga
font-size = 20
font-thicken = true

# Font features for PragmataPro
# Contextual alternate ligatures
font-feature = calt
# Ligatures
font-feature = liga
# Git tree
font-feature = ss13
# Operational and comparison symbols
font-feature = ss14
# Serif
# font-feature = ss16
# BUG // TODO // HACK tags
font-feature = ss18
# Slashed zero
font-feature = zero

# Backward erase word
# This binds cmd+h to alt+backspace which will backward erase one word
# Remember to go change the "Hide Ghostty" menu shortcut to something else, e.g.,
# https://apple.stackexchange.com/questions/101754/os-x-disable-cmd-h-or-hide-app-command
keybind = cmd+h=text:\x1b\x7f
# Forward erase word
keybind = cmd+d=esc:d

# Backward word
keybind = cmd+b=esc:b
# Forward word
keybind = cmd+f=esc:f

# Jump to prompt
keybind = ctrl+up=jump_to_prompt:-1
keybind = ctrl+down=jump_to_prompt:1

# Quick terminal
keybind = global:ctrl+alt+cmd+t=toggle_quick_terminal
quick-terminal-animation-duration = 0.2
quick-terminal-position = top
quick-terminal-screen = mouse

macos-option-as-alt = true
macos-titlebar-style = transparent

mouse-hide-while-typing = true

quit-after-last-window-closed = true

resize-overlay = never

shell-integration = bash
# This fixed an issue w/ the initial Bash cursor showing as a bar instead of a block before a command was executed
# (see cursor-style)
shell-integration-features = no-cursor

theme = light:Gruvbox Light,dark:Gruvbox Dark

window-height = 48
window-width = 110
window-padding-x = 14
window-padding-y = 12
window-padding-balance = true
window-padding-color = extend

Git

CUSTOM_ID: git
header-args: :mkdirp yes :tangle ~/.bashrc.d/105-git.bash

Add completion for my muscle memory alias of g for git:

alias g="git"
type __git_complete >/dev/null 2>&1 && __git_complete g __git_main || true

Diff highlighting (need to review if this is necessary now since I've configured difftastic below).

[ -e "${HOMEBREW_PREFIX}/opt/git/share/git-core/contrib/diff-highlight/" ] && pathmunge "${HOMEBREW_PREFIX}/opt/git/share/git-core/contrib/diff-highlight/"

~/.gitconfig

CUSTOM_ID: gitconfig
header-args: :mkdirp yes :tangle ~/.gitconfig

The includeIf section below allows for sticking a .gitconfig in a directory such that repositories cloned into that directory will read that config for each repository there. This is useful for setting values like email, etc., that might be different than the global value without having to set it specifically in each repository's config. Just clone the repository into this directory and make sure that the config is set. git config --list is useful when making sure that the config values are set properly.

[user]
        name = Kris Molendyke
        email = krismolendyke@users.noreply.github.com
        useconfigonly = true
[color]
        ui = auto
[core]
        excludesfile = ~/.gitignore-global
        whitespace = -trailing-space,-space-before-tab
        editor = emacsclient
[apply]
        whitespace = nowarn
[alias]
        diff = difftool
        stache = stash
        st = status -sb
        a = add -p
        l = log --color-moved --stat --no-merges --ext-diff
        lp = log --color-moved --patch --stat --no-merges --ext-diff
        wlp = log --color-moved --patch --stat --color-words --no-merges --ext-diff
        lo = log --color-moved --oneline --decorate --no-merges --ext-diff
        lf = log --color-moved --pretty=format: --name-only -z --max-count 1 --no-merges --ext-diff
        co = checkout
        br = branch -vv
        wdiff = diff --color-moved --color-words --ext-diff
        ds = diff --color-moved --staged --ext-diff
        g = log --oneline --graph --decorate --all
[advice]
        statusHints = true
[rebase]
        autosquash = true
[diff]
        algorithm = histogram
        colorMoved = zebra
        compactionHeuristic = 1
        external = difft --display=inline
        tool = difftastic
[difftool]
        prompt = false
[difftool "difftastic"]
        cmd = difft --display=inline "$LOCAL" "$REMOTE"
[fetch]
        prune = true
[help]
        autocorrect = 1
[pager]
        difftool = true
[pull]
        rebase = false
[push]
        autoSetupRemote = true
[init]
        defaultBranch = main
[credential]
        helper = cache --timeout=3600
[tag]
        sort = version:refname

# Conditional include to set some work defaults, e.g., email, GHE interal url replacement, ssh signing
# This file is stored in work 1Password Employee vault
[includeIf "gitdir/i:~/code/work/"]
        path = ~/code/work/.gitconfig

~/.gitignore-global

CUSTOM_ID: gitignore-global
header-args: :mkdirp yes :tangle ~/.gitignore-global
# -*- mode: gitignore; -*-

.jj/
.zed/
.bashrc.d/secret/
.claude/
.gemini/
.eca/

##########################################################################
# Below from:                                                            #
#                                                                        #
# https://github.com/github/gitignore/blob/master/Global/Linux.gitignore #
##########################################################################

*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*


##########################################################################
# Below from:                                                            #
#                                                                        #
# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore #
##########################################################################

.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk


##############################################################################
# Below from:                                                                #
#                                                                            #
# https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore #
##############################################################################

# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
.idea/modules.xml
.idea/*.iml
.idea/modules

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

Glow

CUSTOM_ID: glow
header-args: :mkdirp yes :tangle ~/Library/Preferences/glow/glow.yml
---
# style name or JSON path (default "auto")
style: "auto"
# mouse support (TUI-mode only)
mouse: false
# use pager to display markdown
pager: true
# word-wrap at width
width: 120
# show all files, including hidden and ignored.
all: false

Go

CUSTOM_ID: go
header-args: :mkdirp yes :tangle ~/.bashrc.d/106-go.bash
[[ -x "${HOMEBREW_PREFIX}/bin/go" ]] && pathmunge "$("${HOMEBREW_PREFIX}/bin/go" env GOPATH)/bin"

Google Cloud SDK

CUSTOM_ID: google-cloud-sdk
header-args: :mkdirp yes :tangle ~/.bashrc.d/450-google-cloud-sdk.bash

Completion:

# shellcheck source=/dev/null
[ -e "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc" ] && source "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc"
# shellcheck source=/dev/null
[ -e "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc" ] && source "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc"

kubectl, k, kctx, kns, krew

CUSTOM_ID: kubectl-k-kctx-kns-krew
header-args: :mkdirp yes :tangle ~/.bashrc.d/104-kubectl.bash

Completion for my k alias:

alias k="kubectl"
# shellcheck source=/dev/null
[ -e "${HOMEBREW_PREFIX}/etc/bash_completion.d/kubectl" ] && source "${HOMEBREW_PREFIX}/etc/bash_completion.d/kubectl" && complete -o default -F __start_kubectl k

kubectx for wrangling contexts and namespaces:

command -v kubectx >/dev/null 2>&1 && alias kctx="kubectx"
command -v kubens >/dev/null 2>&1 && alias kns="kubens"

Change currently selected color:

KUBECTX_CURRENT_FGCOLOR=$(tput setaf 2)
export KUBECTX_CURRENT_FGCOLOR

TODO krew

CUSTOM_ID: krew

Install and configure krew.

Jujutsu

CUSTOM_ID: jujutsu
header-args: :mkdirp yes :tangle ~/.bashrc.d/991-jujutsu.bash

Enable dynamic completions for things like configured `revset-aliases`, etc.

# shellcheck disable=SC1090
source <(COMPLETE=bash jj)
complete -F _clap_complete_jj -o nosort -o bashdefault -o default jj

jj isn't all that bad to type but I'm conditioned to type g for git after all these years. So j for jj it is.

alias j="jj" && complete -F _clap_complete_jj -o nosort -o bashdefault -o default j

~.config/

CUSTOM_ID: config
header-args: :mkdirp yes :tangle ~/.config/jj/config.toml
"$schema" = "https://jj-vcs.github.io/jj/latest/config-schema.json"

[aliases]
d = ["diff", "--git"]
l = ["log", "--limit", "10"]
rebase-all-onto-trunk = ["rebase", "--source", "roots(trunk()..local_bookmarks)", "--destination", "trunk()"]
tug = ["bookmark", "move", "--from", "heads(::@- & bookmarks())", "--to", "@-"]

[git]
colocate = true

[remotes.origin]
auto-track-bookmarks = 'regex:"^(main|master)$"'
auto-track-created-bookmarks = "*"

[revset-aliases]
'local_bookmarks'.definition = 'bookmarks() & ~trunk()'
'local_bookmarks'.doc = 'Locally tracked bookmarks, not including trunk'

[revsets]
bookmark-advance-to = "@-"
log = "@ | ancestors(@) | ancestors(immutable_heads().., 2) | trunk()"

[signing]
backend = "ssh"
backends.ssh.program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign"
behavior = "own"
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPFEgqTPapPtOUOAsoSH2o4VJbp1JFzvXaiuEpdS0KuK"

[template-aliases]
"format_short_id(id)" = "id.shortest()"
"format_timestamp(timestamp)" = "timestamp.ago()"

[ui]
color = "always"
default-command = ["log", "--revisions", "trunk()::@ | ancestors(trunk(), 2)"]
diff-formatter = "difft"

[user]
email = "krismolendyke@users.noreply.github.com"
name = "Kris Molendyke"

mouseless

CUSTOM_ID: mouseless
header-args: :mkdirp yes :tangle ~/Library/Application Support/Mouseless/configs/config.yaml
# ============================================================
# Dvorak customizations (everything else is v1.0.0 defaults):
#   - keyboard_layout → Dvorak
#   - grid level 1 & 2 keys → Dvorak positions
#   - subgrid_mouse_action_keys → Dvorak positions
#   - free mode → Dvorak positions
# ============================================================

app_version: 1.0.0
behavior_configs:
- base_move_speed: 5.0
  base_wheel_speed: 16.0
  default_mouse_action: click
  free_mode_after_move: false
  free_mode_auto_off_s: 10
  grid_action_level: subgrid
  hide_cursor_on_click: false
  hide_location: bottom_left
  initial_action_location: system_cursor
  initial_overlay_monitor: with_mouse
  mouse_value_cycle_behavior: once
  move_duration_ms: 100
  move_real_cursor_with_virtual: false
  move_speed_multiplier: 3.0
  movement_easing: 0.2
  multi_action_timeout_ms: 400
  name: main_behavior
  send_escape_after_global_alt_tap__windows: true
  tap_threshold_ms: 250
  wheel_easing: 0.3
  wheel_speed_multiplier: 4.0
  wheel_step_size: 100.0
  wheel_step_size_large: 500.0
classname: AppConfig
custom_monitor_assignments: []
custom_mouse_scaling: 1.0
custom_mouse_screen_offset_scaling: 1.0
custom_overlay_scaling: 1.0
debug_options: {}
display_input: none
event_tap_location: session_head
excluded_input_devices: []
general_settings:
  automatically_check_for_updates: true
  check_for_preview_releases: false
  hide_welcome_screen: true
  ignore_update_to_version: null
grid_configs:
- always_show_subgrid: false
  grid_defn:
  - border_width: 0.0
    callback: build_cell_strings
    keys: AOEUI DHTNS
    num_cells_x: 10
    num_cells_y: 1
  - border_width: 1.0
    callback: build_cell_strings
    keys: "',.PY AOEUI ;QJKX FGCRL DHTNS BMWVZ"
    num_cells_x: 1
    num_cells_y: 30
  - border_width: 0.0
    callback: apply_strings_and_subgrid_to_cells
    keys: ''
    num_cells_x: 2
    num_cells_y: 1
  hold_subgrid_key_for_nudge: true
  name: position_based_columns
  nudges_per_cell: 4
  strategy: subgrid
  subgrid_dims:
  - 10
  - 3
  subgrid_mouse_action_keys: "',.PY AOEUI ;QJKX FGCRL DHTNS BMWVZ"
keyboard_layout:
  id: com.apple.keylayout.Dvorak
  name: Dvorak
  vk_to_char:
    0:
    - a
    - A
    1:
    - o
    - O
    2:
    - e
    - E
    3:
    - u
    - U
    4:
    - d
    - D
    5:
    - i
    - I
    6:
    - ;
    - ':'
    7:
    - q
    - Q
    8:
    - j
    - J
    9:
    - k
    - K
    10:
    - "\xA7"
    - "\xB1"
    11:
    - x
    - X
    12:
    - ''''
    - '"'
    13:
    - ','
    - <
    14:
    - .
    - '>'
    15:
    - p
    - P
    16:
    - f
    - F
    17:
    - y
    - Y
    18:
    - '1'
    - '!'
    19:
    - '2'
    - '@'
    20:
    - '3'
    - '#'
    21:
    - '4'
    - $
    22:
    - '6'
    - ^
    23:
    - '5'
    - '%'
    24:
    - ']'
    - '}'
    25:
    - '9'
    - (
    26:
    - '7'
    - '&'
    27:
    - '['
    - '{'
    28:
    - '8'
    - '*'
    29:
    - '0'
    - )
    30:
    - '='
    - +
    31:
    - r
    - R
    32:
    - g
    - G
    33:
    - /
    - '?'
    34:
    - c
    - C
    35:
    - l
    - L
    36: "\r"
    37:
    - n
    - N
    38:
    - h
    - H
    39:
    - '-'
    - _
    40:
    - t
    - T
    41:
    - s
    - S
    42:
    - \
    - '|'
    43:
    - w
    - W
    44:
    - z
    - Z
    45:
    - b
    - B
    46:
    - m
    - M
    47:
    - v
    - V
    48: "\t"
    49: ' '
    50:
    - '`'
    - '~'
    51: "\b"
    52: "\x03"
    53: "\e"
    65: .
    66:
    - "\x1D"
    - '*'
    67: '*'
    69: +
    70:
    - "\x1C"
    - +
    71: "\e"
    72:
    - "\x1F"
    - '='
    75: /
    76: "\x03"
    77:
    - "\x1E"
    - /
    78: '-'
    81: '='
    82: '0'
    83: '1'
    84: '2'
    85: '3'
    86: '4'
    87: '5'
    88: '6'
    89: '7'
    91: '8'
    92: '9'
    96: "\x10"
    97: "\x10"
    98: "\x10"
    99: "\x10"
    100: "\x10"
    101: "\x10"
    102: "\x10"
    103: "\x10"
    104: "\x10"
    105: "\x10"
    106: "\x10"
    107: "\x10"
    108: "\x10"
    109: "\x10"
    110: "\x10"
    111: "\x10"
    112: "\x10"
    113: "\x10"
    114: "\x05"
    115: "\x01"
    116: "\v"
    117: "\x7F"
    118: "\x10"
    119: "\x04"
    120: "\x10"
    121: "\f"
    122: "\x10"
    123: "\x1C"
    124: "\x1D"
    125: "\x1F"
    126: "\x1E"
keymaps:
- entries:
    back click: null
    back mouse button: "'"
    back mouse button (w/o overlay): null
    clear keyboard state: null  # perhaps ctrl+Escape
    close UI element: Escape
    cycle click count: null
    cycle font: '3'
    cycle font reverse: shift+3
    cycle grid action level: '2'
    cycle mouse action type: null
    cycle mouse button: null
    decrease overlay opacity: ArrowDown
    edit config: Tab
    enter free mode: null
    execute mouse action: Space
    execute mouse move: OptionLeft tap
    exit free mode: Escape
    force overlay resize: null
    forward click: null
    forward mouse button: ','
    forward mouse button (w/o overlay): null
    hide overlay: Escape
    hold for back button: null
    hold for drag: CommandLeft
    hold for forward button: null
    hold for free mode: null
    hold for middle button: null
    hold for move: OptionLeft
    hold for right button: CommandRight
    hold for speed decrease: A
    hold for speed increase:
    - S
    - D
    - F
    increase overlay opacity: ArrowUp
    invert colors: null
    jump to bottom: null
    jump to left edge: null
    jump to right edge: null
    jump to top: null
    left click: null
    left mouse button: Space
    left mouse button (w/o overlay): null
    middle click: null
    middle mouse button: D
    middle mouse button (w/o overlay): null
    move down: T
    move left: H
    move right: N
    move up: C
    release hold/drag: Escape
    repeat last mouse action: null
    right click: null
    right mouse button: P
    right mouse button (w/o overlay): null
    show overlay: CommandLeft tap
    subgrid nudge down:
    - E
    - T
    subgrid nudge left:
    - O
    - H
    subgrid nudge right:
    - U
    - N
    subgrid nudge up:
    - .
    - C
    switch monitor left: ShiftLeft tap
    switch monitor right: ShiftRight tap
    toggle app enabled: null
    toggle continuous mode: null
    toggle continuous mode until closed: '1'
    toggle free mode: OptionLeft tap
    toggle overlay: null
    toggle overlay lock: null
    undo last key: Backspace
    wheel down: K
    wheel down fast: null
    wheel left: G
    wheel left fast: null
    wheel right: R
    wheel right fast: null
    wheel step down: null
    wheel step down large: null
    wheel step left: null
    wheel step left large: null
    wheel step right: null
    wheel step right large: null
    wheel step up: null
    wheel step up large: null
    wheel up: L
    wheel up fast: null
  name: mac
log_level: info
mac_hud_window_level: 1001
monitor_assignment_mode: auto
mouse_scaling: auto
mouse_screen_offset_scaling: auto
name: ''
overlay_scaling: auto
style_configs:
- always_on_subgrid_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 0.2
  background_colors:
  - - 0.49
    - 0.4
    - 0.0
    - 0.35
  bg_color_block_size: 1
  bg_color_transforms_level_1:
  - - hsla_add
    - 0.0
    - 0.0
    - 0.0
    - 0.0
  bg_color_transforms_level_2:
  - - hsla_add
    - 0.0
    - 0.0
    - 0.0
    - 0.0
  char_anchor: center
  char_display: all
  char_spacing_cell_width_ratio: 0.5
  char_spacing_font_size_ratio: 0.5
  char_spacing_strategy: cell_width_relative
  colorParamInput: none
  cursor_drag_rgba:
  - 0.0
  - 0.5
  - 1.0
  - 0.7
  cursor_move_rgba:
  - 0.75
  - 0.41
  - 0.92
  - 0.7
  cursor_other_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 0.7
  cursor_rgba:
  - 0.3
  - 0.42
  - 0.58
  - 0.8
  cursor_right_button_rgba:
  - 0.92
  - 0.32
  - 0.32
  - 0.7
  cursor_size: 7
  font_family: 'PragmataProVFLiga-Regular'
  font_size_multiplier: 0.4
  font_weight: 700
  free_mode_indicator_offset_x: 20.0
  free_mode_indicator_offset_y: 20.0
  free_mode_indicator_rgba:
  - 0.3
  - 0.42
  - 0.58
  - 0.9
  free_mode_indicator_size: 10
  free_mode_status_display: both
  grid_line_style: lines
  grid_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 0.5
  highlight_animation_ms: 0
  highlight_rgba:
  - 0.21
  - 0.48
  - 0.95
  - 0.2
  name: default
  show_initial_highlight: false
  subgrid_font_size_multiplier: 1.0
  subgrid_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 0.5
  subgrid_text_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 0.9
  text_rgba:
  - 1.0
  - 1.0
  - 1.0
  - 1.0
  text_shadow_blur_radius: 3.0
  text_shadow_offset:
  - 0.0
  - 0.0
  text_shadow_rgba:
  - 0.0
  - 0.0
  - 0.0
  - 1.0
  text_y_offset: 0.0
  toast_opacity: 0.5
  use_bg_color_transforms: false
  window_opacity: 1.0

Nushell

CUSTOM_ID: nushell

The complete Nushell configuration is grouped here for easy review. Follow the links to each tool's main section for shared documentation and Bash configuration.

config.nu

CUSTOM_ID: config-nu
header-args: :mkdirp yes :tangle ~/Library/Application Support/nushell/config.nu
###############
# Environment #
###############

$env.SSH_AUTH_SOCK = ($env.HOME | path join ".1password/agent.sock")
$env.GOPATH = ($env.HOME | path join "code/go")
$env.EDITOR = "emacsclient"
$env.VISUAL = "emacsclient"
$env.DFT_DISPLAY = "side-by-side-show-both"
$env.RIPGREP_CONFIG_PATH = ($env.HOME | path join ".ripgreprc")

$env.PATH = (
    $env.PATH
    | split row (char esep)
    | prepend '/opt/homebrew/bin'
    | prepend '/opt/homebrew/sbin'
    | prepend '/usr/local/bin'
    | prepend '/usr/local/sbin'
    | prepend ($env.HOME | path join '.cargo/bin')
    | prepend ($env.HOME | path join 'code/go/bin')
    | prepend ($env.HOME | path join '.local/bin')
    | prepend ($env.HOME | path join 'bin')
    | prepend '/opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/bin'
    | uniq
)


###########
# Secrets #
###########

# Load secrets from ~/.bashrc.d/secret/secrets.env or an optional specified file
def --env k20e_load_secrets [file?: path] {
    let secrets_env = ($file | default ($env.HOME | path join ".bashrc.d/secret/secrets.env"))
    if ($secrets_env | path exists) {
        open $secrets_env
        | lines
        | where { $in =~ '^[A-Za-z0-9_]+=' }
        | parse "{key}={value}"
        | reduce -f {} {|it, acc| $acc | insert $it.key ($it.value | str trim -c '"' | str trim -c "'") }
        | load-env
    }
}

# Initial load of secrets on shell startup
k20e_load_secrets


###########
# Aliases #
###########

alias g = git
alias j = jj
alias k = kubectl
alias c = claude
alias l = ls
alias ll = ls -l

# Quick runner for bash one-liners / scripts
def --wrapped b [...cmd] {
    ^bash -c ($cmd | str join ' ')
}

def --env r [] {
    let jj_root = (do { ^jj root } | complete)
    let root = if $jj_root.exit_code == 0 {
        $jj_root.stdout | str trim
    } else {
        let git_root = (do { ^git rev-parse --show-toplevel } | complete)
        if $git_root.exit_code == 0 {
            $git_root.stdout | str trim
        } else {
            ""
        }
    }
    if ($root | is-not-empty) and ($root != $env.PWD) {
        cd $root
    }
}


def 'is-installed' [ app: string ] {
  which $app | is-not-empty
}


$env.config.buffer_editor = "emacsclient"


# Universal LS_COLORS palette optimized for both Light and Dark terminal backgrounds
$env.LS_COLORS = "di=01;34:ln=01;36:so=01;35:pi=01;33:ex=01;32:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43"


#######################
# Conditional aliases #
#######################

def cat [...args] {
  if (is-installed bat) {
    ^bat --theme auto:system --theme-dark default --theme-light GitHub ...$args
  } else {
    ^cat ...$args
  }
}


###############
# Completions #
###############

$env.CARAPACE_BRIDGES = "zsh,fish,bash"

let carapace_cache = ($nu.data-dir | path join "vendor/autoload/carapace.nu")
if not ($carapace_cache | path exists) and (is-installed carapace) {
    mkdir ($nu.data-dir | path join "vendor/autoload")
    carapace _carapace nushell | save -f $carapace_cache
}

let carapace_aliases = {
    g: "git"
    j: "jj"
    k: "kubectl"
    c: "claude"
    ec: "emacsclient"
    l: "ls"
    ll: "ls"
}

def carapace-completer [spans: list<string>] {
    let expanded_spans = if ($spans.0 in $carapace_aliases) {
        $spans | skip 1 | prepend ($carapace_aliases | get $spans.0)
    } else {
        $spans
    }

    with-env { CARAPACE_LENIENT: "1" } {
        ^carapace $expanded_spans.0 nushell ...$expanded_spans
    } | from json
}

$env.config.completions.external = {
    enable: true
    max_results: 100
    completer: {|spans| carapace-completer $spans}
}


###############
# Keybindings #
###############

$env.config.keybindings = ($env.config.keybindings | append [
    {
        name: emacs_cancel_abort
        modifier: control
        keycode: char_g
        mode: [emacs, vi_insert, vi_normal]
        event: { send: ctrlc }
    }
])


############
# Starship #
############

let starship_cache = ($nu.data-dir | path join "vendor/autoload/starship.nu")
if not ($starship_cache | path exists) and (is-installed starship) {
    mkdir ($nu.data-dir | path join "vendor/autoload")
    starship init nu | save -f $starship_cache
}


$env.config.show_banner = "short" # just show startup time

Emacs

CUSTOM_ID: emacs-nushell
header-args: :mkdirp yes :tangle ~/Library/Application Support/nushell/autoload/107-emacs.nu

See Emacs.

# Support opening files at a line number with the :linum suffix, mirroring k20e_ec
def ec [file?: string, ...rest] {
    if ($file != null) and ($file =~ '^(.+):(\d+)(?::\d+)?$') {
        let m = ($file | parse -r '^(?P<path>.+):(?P<line>\d+)')
        ^emacsclient -n $"+($m.0.line)" $m.0.path ...$rest
    } else if ($file != null) {
        ^emacsclient -n $file ...$rest
    } else {
        ^emacsclient -n ...$rest
    }
}

Skills Wrapper

CUSTOM_ID: skills-nushell-wrapper
header-args: :mkdirp yes :tangle ~/Library/Application Support/nushell/autoload/109-skills.nu

See Skills.

def k20e_agent_skills_sync [...args] {
    ^k20e-skills-sync ...$args
}

eza

CUSTOM_ID: eza-nushell
header-args: :mkdirp yes :tangle ~/Library/Application Support/nushell/autoload/130-eza.nu

See eza.

alias lt = ^eza --classify --git --git-repos --tree
alias ltl = ^eza --classify --git --git-repos --tree --long --header --smart-group

Television

CUSTOM_ID: television-nushell
header-args: :mkdirp yes :tangle ~/Library/Application Support/nushell/autoload/140-television.nu

See Television.

def tv_smart_autocomplete [] {
    let line = (commandline)
    let cursor = (commandline get-cursor)
    let lhs = ($line | str substring 0..$cursor)
    let rhs = ($line | str substring $cursor..)
    let output = (tv --no-status-bar --inline --autocomplete-prompt $lhs | str trim)

    if ($output | str length) > 0 {
        let needs_space = not ($lhs | str ends-with " ")
        let lhs_with_space = if $needs_space { $"($lhs) " } else { $lhs }
        let new_line = $lhs_with_space + $output + $rhs
        let new_cursor = ($lhs_with_space + $output | str length)
        commandline edit --replace $new_line
        commandline set-cursor $new_cursor
    }
}

def tv_shell_history [] {
    let current_prompt = (commandline)
    let cursor = (commandline get-cursor)
    let current_prompt = ($current_prompt | str substring 0..$cursor)

    let output = (tv nu-history --no-status-bar --inline --input $current_prompt | str trim)

    if ($output | is-not-empty) {
        commandline edit --replace $output
        commandline set-cursor --end
    }
}

if (which tv | is-not-empty) {
    $env.config.keybindings = (
        $env.config.keybindings
        | append [
            # tv_smart_autocomplete on Ctrl-T omitted so Ctrl-T transposes characters
            {
                name: transpose_chars
                modifier: control
                keycode: char_t
                mode: [emacs, vi_insert]
                event: { edit: SwapGraphemes }
            }
            {
                name: tv_history
                modifier: control
                keycode: char_r
                mode: [vi_normal, vi_insert, emacs]
                event: {
                    send: executehostcommand
                    cmd: "tv_shell_history"
                }
            }
        ]
    )
}

History Channel

CUSTOM_ID: nushell-history
header-args: :mkdirp yes :tangle ~/.config/television/cable/nu-history.toml
[metadata]
name = "nu-history"
description = "A channel to select from your nu history"

[source]
command = "nu -c 'open $nu.history-path | lines | uniq | reverse | to text'"
no_sort = true
frecency = false

OCaml

CUSTOM_ID: ocaml
header-args: :mkdirp yes :tangle ~/.bashrc.d/500-opam.bash

Modified output of opam init:

# shellcheck source=/dev/null
[ -e "${HOME}/.opam/opam-init/init.sh" ] && source "${HOME}/.opam/opam-init/init.sh"

OpenRouter

CUSTOM_ID: openrouter

ori

CUSTOM_ID: ori

ori is OpenRouter's official harness for running coding agent CLIs (Claude Code, Codex, Hermes, OpenCode, Pi, etc.) on OpenRouter models with OAuth PKCE authentication. Because ori authenticates via browser OAuth and wraps agent processes directly, it avoids the need to export global ANTHROPIC_* environment variables, ensuring enterprise credentials remain completely untouched on work machines.

Install or update:

# Install standalone ori to ~/.local/bin/ori (on PATH for Bash and Nushell)
curl -fsSL https://openrouter.ai/labs/ori/install.sh | bash

# Update
ori update

Launch Claude Code via OpenRouter:

ori claude

Environment & Downstream Tools

CUSTOM_ID: openrouter-env

For non-harness tools that consume OpenRouter directly (such as eca, OpenUsage, LiteLLM, or local routers like jev-router), the secret OPENROUTER_API_KEY from https://openrouter.ai/keys lives with my other secrets in ~/.bashrc.d/secret/secrets.env (managed via personal 1Password vault).

# OpenRouter API Key
OPENROUTER_API_KEY="..."

The actual OpenRouter provider/model routing config (which models, privacy/data-collection preferences, etc.) for eca is configured as part of eca's openrouter provider — see the eca section above.

OpenUsage

CUSTOM_ID: openusage

openusage tracks my OpenRouter spend. Since OpenUsage falls back to checking the OPENROUTER_API_KEY environment variable, a local configuration file is not required.

Playdate

CUSTOM_ID: playdate
header-args: :mkdirp yes :tangle ~/.bashrc.d/511-playdate.bash
[ -e "${HOME}/Developer/PlaydateSDK" ] && export PLAYDATE_SDK_PATH="${HOME}/Developer/PlaydateSDK" && pathmunge "${PLAYDATE_SDK_PATH}/bin"

Rancher

CUSTOM_ID: rancher
header-args: :mkdirp yes :tangle ~/.bashrc.d/560-rancher.bash
[ -d "${HOME}/.rd/bin" ] && pathmunge "${HOME}/.rd/bin"

ripgrep

CUSTOM_ID: ripgrep
header-args: :mkdirp yes :tangle ~/.bashrc.d/510-ripgrep.bash
export RIPGREP_CONFIG_PATH=${HOME}/.ripgreprc

The Nushell equivalent lives in config.nu.

~/.ripgreprc

CUSTOM_ID: ripgreprc
header-args: :mkdirp yes :tangle ~/.ripgreprc

See RIPGREP_CONFIG_PATH above and https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file

--sort-files

Rust

CUSTOM_ID: rust
header-args: :mkdirp yes :tangle ~/.bashrc.d/550-rust.bash

See https://github.com/rust-lang-nursery/rustfmt#tips.

if [ -d "${HOME}/.cargo" ]; then
    export CARGO_HOME=${HOME}/.cargo
    pathmunge "${CARGO_HOME}/bin"
fi

if [[ -x ${HOMEBREW_PREFIX}/bin/rustc ]]; then
    DYLD_LIBRARY_PATH=$("${HOMEBREW_PREFIX}"/bin/rustc --print sysroot)/lib:${DYLD_LIBRARY_PATH}
    export DYLD_LIBRARY_PATH
fi

ShellCheck

CUSTOM_ID: shellcheck
header-args: :mkdirp yes :tangle ~/.bashrc.d/300-shellcheck.bash

k20e_shellcheck will run shellcheck against the result of tangling all of this configuration to the files that the shell will actually execute.

command -v shellcheck >/dev/null 2>&1 && alias k20e_shellcheck='find $HOME/.bash_profile $HOME/.bashrc $K20E_BASHRC_DIR -type f -exec shellcheck '\''{}'\'' +'

~/.shellcheckrc

CUSTOM_ID: shellcheckrc
header-args: :mkdirp yes :tangle ~/.shellcheckrc
color=always
shell=bash

SSH

CUSTOM_ID: ssh

On macOS, 1Password requires this to work with the Environment properly:

mkdir -p ~/.1password && ln -s ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock ~/.1password/agent.sock

~/.ssh/config

CUSTOM_ID: ssh-config
header-args: :mkdirp yes :tangle ~/.ssh/config
ServerAliveCountMax 5
ServerAliveInterval 60

Host *
    IdentityAgent ~/.1password/agent.sock
    StrictHostKeyChecking accept-new

Include ~/.ssh/config.d/*

Personal

CUSTOM_ID: personal
header-args: :mkdirp yes :tangle ~/.ssh/config.d/personal

Splitting work & personal to allow for using multiple GitHub accounts. See https://developer.1password.com/docs/ssh/agent/advanced/#use-multiple-github-accounts.

Host personal.localhost
     HostName github.com
     User git
     IdentityFile ~/.ssh/personal.pub
     IdentitiesOnly yes
     PreferredAuthentications publickey
     PasswordAuthentication no

Work

CUSTOM_ID: work
header-args: :mkdirp yes :tangle ~/.ssh/config.d/work
Host work.localhost
     HostName github.com
     User git
     IdentityFile ~/.ssh/work.pub
     IdentitiesOnly yes
     PreferredAuthentications publickey
     PasswordAuthentication no

Environment

CUSTOM_ID: environment
header-args: :mkdirp yes :tangle ~/.bashrc.d/101-ssh-env.bash
export SSH_AUTH_SOCK=~/.1password/agent.sock

Skills

CUSTOM_ID: skills

Synchronizes external agent skills (e.g. krismolendyke/jujutsu-skill) to each configured agent's skills location. Each skill is kept as a canonical jj clone under ~/.local/share/agent-skills/<name>/ and materialized (copied) into all four agents, so one jj git fetch keeps all current.

Each entry is a skill repository. Every SKILL.md it contains (at most one level deep) is installed to all four agents (claude, eca, gemini, and agy); the skill name is taken from the folder holding it. Add a new skill by appending a repo URL.

Standalone CLI (~/.local/bin/k20e-skills-sync)

CUSTOM_ID: skills-sync-cli
header-args: :mkdirp yes :tangle ~/.local/bin/k20e-skills-sync :shebang "#!/usr/bin/env bash"
set -euo pipefail

K20E_AGENT_SKILL_REPOS=(
    "https://github.com/krismolendyke/jujutsu-skill"
)

cache_dir="${XDG_DATA_HOME:-$HOME/.local/share}/agent-skills"
mkdir -p "$cache_dir"
for url in "${K20E_AGENT_SKILL_REPOS[@]}"; do
    name="${url##*/}"
    name="${name%.git}"
    clone_dir="$cache_dir/$name"
    if [[ ! -d "$clone_dir/.jj" && ! -d "$clone_dir/.git" ]]; then
        jj git clone "$url" "$clone_dir" >/dev/null 2>&1
    else
        jj -R "$clone_dir" git remote set-url origin "$url" 2>/dev/null || true
        jj -R "$clone_dir" git fetch --remote origin --quiet
        jj -R "$clone_dir" new 'trunk()' >/dev/null 2>&1
    fi
    trunk_info="$(jj -R "$clone_dir" log -r 'trunk()' --no-graph -T 'change_id.shortest() ++ ": " ++ description.first_line()' 2>/dev/null || true)"
    while IFS= read -r skill_file; do
        skill_dir="$(dirname "$skill_file")"
        skill_name="$(basename "$skill_dir")"
        for agent_dir in \
            "$HOME/.claude/skills/$skill_name" \
            "$HOME/.config/eca/skills/$skill_name" \
            "$HOME/.gemini/skills/$skill_name" \
            "$HOME/.gemini/config/skills/$skill_name"; do
            mkdir -p "$agent_dir"
            cp -R "$skill_dir/"* "$agent_dir/"
        done
        echo "✓ Synced $skill_name from $url"
        if [[ -n "$trunk_info" ]]; then
            echo "  Trunk tip: $trunk_info"
        fi
    done < <(find "$clone_dir" -maxdepth 2 -name SKILL.md \
        -not -path '*/.jj/*' -not -path '*/.git/*')
done

Bash Wrapper

CUSTOM_ID: skills-bash-wrapper
header-args: :mkdirp yes :tangle ~/.bashrc.d/109-skills.bash
k20e_agent_skills_sync() {
    k20e-skills-sync "$@"
}

Trigger the sync from Emacs: put point in the block below and run C-c C-c.

k20e-skills-sync

Starship

CUSTOM_ID: starship
header-args: :mkdirp yes :tangle ~/.bashrc.d/999-starship.bash
if command -v starship >/dev/null 2>&1; then
    function k20e_starship_precmd_user_func() {
        # Immediately append commands to HISTFILE rather than waiting for logout
        # NB this does not affect the current session's history but it does mean that a login will have access to all
        # recent commands from any current sessions
        history -a
    }
    # See https://starship.rs/advanced-config/#custom-pre-prompt-and-pre-execution-commands-in-bash
    # shellcheck disable=SC2034
    starship_precmd_user_func='k20e_starship_precmd_user_func'

    # Only init one time, I found issues w/ this executing multiple time, e.g., via interactive `source ~/.bashrc`
    if [[ -z "${STARSHIP_SHELL-}" ]]; then
        eval "$(starship init bash)"
    fi
fi

~/.config/starship.toml

CUSTOM_ID: config-starship-toml
header-args: :mkdirp yes :tangle ~/.config/starship.toml

https://starship.rs/config/#prompt

CUSTOM_ID: prompt

This section must be first!

# Get editor completions based on the config schema
"$schema" = 'https://starship.rs/config-schema.json'

format = """
${custom.nushell}\
$aws\
$gcloud\
${custom.gcloud_prod}\
$kubernetes\
$docker_context\
${custom.jj} \
$line_break\
$username\
$hostname\
$localip\
$shlvl\
$directory\
$git_branch\
$git_commit\
$git_state\
$git_metrics\
$git_status\
$package\
$c\
$cmake\
$golang\
$helm\
$java\
$julia\
$kotlin\
$gradle\
$lua\
$nodejs\
$opa\
$perl\
$python\
$ruby\
$rust\
$scala\
$swift\
$terraform\
$zig\
$buf\
$memory_usage\
$env_var\
$crystal\
$custom\
$sudo\
$cmd_duration\
$line_break\
$jobs\
$battery\
$time\
$status\
$os\
$container\
$shell\
$character"""

Presets

CUSTOM_ID: presets

Started with starship preset nerd-font-symbols and removed stuff I'll never need.

[buf]
symbol = " "

[c]
symbol = " "

[hostname]
ssh_symbol = " "

[java]
symbol = " "

[lua]
symbol = " "

[memory_usage]
symbol = "󰍛 "

[nodejs]
symbol = " "

[ocaml]
symbol = " "

[os.symbols]
Alpine = " "
Amazon = " "
Android = " "
Arch = " "
CentOS = " "
Debian = " "
Linux = " "
Macos = " "
Raspbian = " "
Redhat = " "
RedHatEnterprise = " "
Ubuntu = " "
Unknown = " "

[ruby]
symbol = " "

[rust]
symbol = " "

https://starship.rs/config/#aws

CUSTOM_ID: aws
[aws]
symbol = 'aws '
format = '[$symbol($profile )(\($region\) )(\[$duration\] )]($style)'

https://starship.rs/config/#battery

CUSTOM_ID: battery
[battery]
disabled = true

https://starship.rs/config/#character

CUSTOM_ID: character
[character]
success_symbol = '[#](bold green)'
error_symbol = '[#](bold red)'

https://starship.rs/config/#command-duration

CUSTOM_ID: command-duration
[cmd_duration]
format = '[$duration]($style) '

https://starship.rs/config/#directory

CUSTOM_ID: directory
[directory]
read_only = ' 󰌾'
truncation_length = 8
truncation_symbol = '…/'
truncate_to_repo = true
format ='[$path]($style)[$read_only]($read_only_style) '

https://starship.rs/config/#docker-context

CUSTOM_ID: docker-context
[docker_context]
symbol = ''
format = '[$symbol $context]($style) '

https://starship.rs/config/#go

CUSTOM_ID: config-starship-toml-go
[golang]
symbol = '󰟓 '
format = '[$symbol($version )]($style) '

https://starship.rs/config/#google-cloud-gcloud

CUSTOM_ID: google-cloud-gcloud
[gcloud]
symbol = 'gcp '
format = '[$symbol$project( \($region\))]($style) '

https://starship.rs/config/#google-cloud-gcloud-prod-warning

CUSTOM_ID: google-cloud-gcloud-prod-warning
[custom.gcloud_prod]
command = """
project="${CLOUDSDK_CORE_PROJECT:-${GCLOUD_PROJECT}}"
if [[ -z "$project" ]]; then
  conf_dir="${CLOUDSDK_CONFIG:-$HOME/.config/gcloud}"
  if [[ -r "$conf_dir/active_config" ]]; then
    active_conf=$(< "$conf_dir/active_config")
    conf_file="$conf_dir/configurations/config_$active_conf"
    if [[ -r "$conf_file" ]]; then
      while read -r line || [[ -n "$line" ]]; do
        if [[ "$line" =~ ^project[[:space:]]*=[[:space:]]*(.*) ]]; then
          project="${BASH_REMATCH[1]}"
          break
        fi
      done < "$conf_file"
    fi
  fi
fi
if [[ "$project" == "ufp-prod" ]]; then
  echo "🚨 PROD 🚨"
fi
"""
when = true
shell = ["bash", "--norc", "--noprofile"]
style = "bold red"
format = "[$output]($style) "

https://starship.rs/config/#git-branch

CUSTOM_ID: git-branch
[git_branch]
always_show_remote = false
symbol = ''
format = '[$symbol $branch(:$remote_branch)]($style) '
disabled = true

[custom.git_branch]
when = "! jj --ignore-working-copy root"
command = "starship module git_branch"
description = "Only show git_branch if we're not in a jj repo"
style = ""
shell = ["bash", "--norc", "--noprofile"]

https://starship.rs/config/#git-commit

CUSTOM_ID: git-commit
[git_commit]
disabled = true

[custom.git_commit]
when = "! jj --ignore-working-copy root"
command = "starship module git_commit"
style = ""
description = "Only show git_commit if we're not in a jj repo"
shell = ["bash", "--norc", "--noprofile"]

https://starship.rs/config/#git-status

CUSTOM_ID: git-status
[git_status]
# all_status = '$conflicted$stashed$deleted$renamed$modified$staged$untracked'
format = '([$conflicted$deleted$renamed$modified$staged$untracked$ahead_behind]($style) )'
disabled = true

[custom.git_status]
when = "! jj --ignore-working-copy root"
command = "starship module git_status"
style = "" # This disables the default "(bold green)" style
description = "Only show git_status if we're not in a jj repo"
shell = ["bash", "--norc", "--noprofile"]

Jujutsu

CUSTOM_ID: config-starship-toml-jujutsu

No official support yet, need to install this tool https://gitlab.com/lanastara_foss/starship-jj before configuring. See also https://github.com/starship/starship/issues/6076.

[custom.jj]
command = "prompt"
format = "$output"
ignore_timeout = true
shell = ["starship-jj", "--ignore-working-copy", "starship"]
use_stdin = false
when = true
  • ~/.config/starship-jj/starship-jj.toml
    CUSTOM_ID: config-starship-jj-starship-jj-toml
    header-args: :mkdirp yes :tangle ~/.config/starship-jj/starship-jj.toml
    

    https://gitlab.com/lanastara_foss/starship-jj

    # Get editor completions based on the config schema
    "$schema" = 'https://gitlab.com/lanastara_foss/starship-jj/-/raw/main/schema.json'
    
    module_separator = " "
    reset_color = false
    
    [bookmarks]
    search_depth = 100
    exclude = []
    
    [[module]]
    type = "Symbol"
    symbol = "📚"
    color = "Blue"
    
    [[module]]
    type = "Bookmarks"
    separator = " "
    color = "Magenta"
    behind_symbol = " "
    ignore_empty_commits = "All"
    surround_with_quotes = false
    
    [[module]]
    type = "Commit"
    color = "Yellow"
    max_length = 48
    empty_text = "no description set"
    surround_with_quotes = false
    show_previous_if_empty = true
    previous_message_symbol="↓"
    
    [[module]]
    type = "State"
    separator = " "
    
    [module.conflict]
    disabled = false
    text = "💥"
    color = "Red"
    
    [module.divergent]
    disabled = false
    text = "🚧"
    color = "Cyan"
    
    [module.empty]
    disabled = false
    text = "∅"
    color = "Yellow"
    
    [module.immutable]
    disabled = false
    text = "🔒"
    color = "Yellow"
    
    [module.hidden]
    disabled = false
    text = "👻"
    color = "Yellow"
    
    [[module]]
    type = "Metrics"
    template = "[{changed} {added}{removed}]"
    color = "Magenta"
    
    [module.changed_files]
    prefix = ""
    suffix = ""
    color = "Cyan"
    
    [module.added_lines]
    prefix = "+"
    suffix = ""
    color = "Green"
    
    [module.removed_lines]
    prefix = "-"
    suffix = ""
    color = "Red"
    

https://starship.rs/config/#kubernetes

CUSTOM_ID: kubernetes
[kubernetes]
disabled = false
symbol = 'k8s '
format = '[$symbol$context( \($namespace\))]($style) '

Nushell

CUSTOM_ID: config-starship-toml-nushell

Show a 🐚 icon when in Nushell

[custom.nushell]
when = '''[[ "$STARSHIP_SHELL" == "nu" ]]'''
symbol = "🐚"
format = "[$symbol]($style) "
style = "bold green"
shell = ["bash"]

https://starship.rs/config/#package-version

CUSTOM_ID: package-version
[package]
format = '[$symbol$version]($style) '
symbol = '󰏗 '

https://starship.rs/config/#python

CUSTOM_ID: python
[python]
symbol = ' '
format = '[${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'

https://starship.rs/config/#terraform

CUSTOM_ID: config-starship-toml-terraform
[terraform]
format = '[$symbol$workspace]($style) '

Television

CUSTOM_ID: television

A fuzzy finder https://alexpasmantier.github.io/television/

Smart Autocomplete & Shell History

CUSTOM_ID: smart-autocomplete-shell-history
header-args: :mkdirp yes :tangle ~/.bashrc.d/140-television.bash

Modified output of tv init bash:

if command -v tv >/dev/null 2>&1; then
   function tv_smart_autocomplete() {
       local current_prompt="${READLINE_LINE:0:$READLINE_POINT}"

       local output
       output=$(tv --autocomplete-prompt "$current_prompt")

       if [[ -n $output ]]; then
           # add a space if the prompt does not end with one
           [[ "${current_prompt}" != *" " ]] && current_prompt="${current_prompt} "

           READLINE_LINE=$current_prompt$output
           READLINE_POINT=${#READLINE_LINE}
       fi
   }

   function tv_shell_history() {
       local current_prompt="${READLINE_LINE:0:$READLINE_POINT}"

       local output
       output=$(tv --no-preview bash-history --input "$current_prompt")

       if [[ -n $output ]]; then
           READLINE_LINE=$output
           READLINE_POINT=${#READLINE_LINE}
       fi
   }

   bind -x '"\C-X\C-T": tv_smart_autocomplete' # NB I need C-t as transpose-chars
   bind '"\C-t": transpose-chars'
   bind -x '"\C-R": tv_shell_history'
fi

Configuration

CUSTOM_ID: television-configuration
header-args: :mkdirp yes :tangle ~/.config/television/config.toml

Modified from https://github.com/alexpasmantier/television/blob/main/.config/config.toml

# CONFIGURATION FILE LOCATION ON YOUR SYSTEM:
# -------------------------------------------
# Defaults:
# ---------
#  Linux:   `$HOME/.config/television/config.toml`
#  macOS:   `$HOME/.config/television/config.toml`
#  Windows: `%APPDATA%\television\config.toml`
#
# XDG dirs:
# ---------
# You may use XDG_CONFIG_HOME if set on your system.
# In that case, television will expect the configuration file to be in:
# `$XDG_CONFIG_HOME/television/config.toml`
#

# General settings
# ----------------------------------------------------------------------------
tick_rate = 50

[ui]
# How much space to allocate for the UI (in percentage of the screen)
# ┌───────────────────────────────────────┐
# │                                       │
# │            Terminal screen            │
# │    ┌─────────────────────────────┐    │
# │    │                             │    │
# │    │                             │    │
# │    │                             │    │
# │    │       Television UI         │    │
# │    │                             │    │
# │    │                             │    │
# │    │                             │    │
# │    │                             │    │
# │    └─────────────────────────────┘    │
# │                                       │
# │                                       │
# └───────────────────────────────────────┘
ui_scale = 100
# The theme to use for the UI
# A list of builtin themes can be found in the `themes` directory of the television
# repository. You may also create your own theme by creating a new file in a `themes`
# directory in your configuration directory (see the `config.toml` location above).
theme = "default"

[ui.input_bar]
# Where to place the input bar in the UI (top or bottom)
position = "bottom"

[ui.help_panel]
# Whether to split the help panel by categories
show_categories = true
hidden = true

[ui.preview_panel]
# Preview panel size (percentage of screen width/height)
size = 50
#header = ""
#footer = ""
scrollbar = true
border_type = "rounded"
# padding = {"left": 0, "right": 0, "top": 0, "bottom": 0}
hidden = false

# Previewers settings
# ----------------------------------------------------------------------------
[previewers.file]
# The theme to use for syntax highlighting.
# Bulitin syntax highlighting uses the same syntax highlighting engine as bat.
# To get a list of your currently available themes, run `bat --list-themes`
# Note that setting the BAT_THEME environment variable will override this setting.
theme = "TwoDark"

# Keybindings
# ----------------------------------------------------------------------------
#
# Channel mode
# ------------------------
[keybindings]
# Quit the applicatione
esc = "quit"
ctrl-c = "quit"
ctrl-g = "quit"
# Scrolling through entries
down = "select_next_entry"
ctrl-n = "select_next_entry"
ctrl-j = "select_next_entry"
up = "select_prev_entry"
ctrl-p = "select_prev_entry"
ctrl-k = "select_prev_entry"
pagedown = "select_next_page"
pageup = "select_prev_page"
# Scrolling the preview pane
ctrl-d = "scroll_preview_half_page_down"
ctrl-u = "scroll_preview_half_page_up"
# Add entry to selection and move to the next entry
tab = "toggle_selection_down"
# Add entry to selection and move to the previous entry
backtab = "toggle_selection_up"
# Confirm selection
enter = "confirm_selection"
# Copy the selected entry to the clipboard
ctrl-y = "copy_entry_to_clipboard"
# Toggle the remote control mode
ctrl-r = "toggle_remote_control"
# Toggle the send to channel mode
# ctrl-s = "toggle_send_to_channel"
# Toggle the help bar
ctrl-h = "toggle_help"
# Toggle the preview panel
ctrl-o = "toggle_preview"

# Shell integration
# ----------------------------------------------------------------------------
#
# The shell integration feature allows you to use television as a picker for
# your shell commands (as well as your shell history with <CTRL-R>).
# E.g. typing `git checkout <CTRL-T>` will open television with a list of
# branches to choose from.

[shell_integration.channel_triggers]
# Add your channel triggers here. Each key is a channel that will be triggered
# by the corresponding commands.
# Example: say you want the following commands to trigger the following channels
# when pressing <CTRL-T>:
#          `git checkout`  should trigger the `git-branches` channel
#          `ls`            should trigger the `dirs` channel
#          `cat` and `cp`  should trigger the `files` channel
#
# You would add the following to your configuration file:
# ```
# [shell_integration.channel_triggers]
# "git-branches" = ["git checkout"]
# "dirs" = ["ls"]
# "files" = ["cat", "cp"]
# ```
"alias" = ["alias", "unalias"]
"dirs" = [
  "cd",
  "ls",
  "ll",
  "ltl",
  "rmdir",
]
"docker-images" = ["docker run"]
"env" = ["export", "unset"]
"files" = [
  "cat",
  "less",
  "head",
  "tail",
  "vim",
  "nano",
  "bat",
  "cp",
  "mv",
  "rm",
  "touch",
  "chmod",
  "chown",
  "ln",
  "tar",
  "zip",
  "unzip",
  "gzip",
  "gunzip",
  "xz",
]
"jj-log" = ["j show",]


[shell_integration.keybindings]
# controls which key binding should trigger tv
# for shell autocomplete
# "smart_autocomplete" = "ctrl-t"
# controls which keybinding should trigger tv
# for command history
"command_history" = "ctrl-r"

Cable Channels

CUSTOM_ID: cable-channels

Modified from https://github.com/alexpasmantier/television/tree/main/cable/unix

TODO migrate these to the 0.12+ format :/

[[cable_channel]]
name = "docker-images"
source_command = "docker image list --format \"{{.ID}}\""
preview_command = "docker image inspect {0} | jq -C"

Bash History

CUSTOM_ID: bash-history
header-args: :mkdirp yes :tangle ~/.config/television/cable/bash-history.toml
[metadata]
name = "bash-history"
description = "A channel to select from your bash history"
requirements = ["bash"]

[source]
command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.bash_history} | rg -v '^#' | nl | sort -k2 -u | sort -n | cut -f 2"

Bash Dotfiles

CUSTOM_ID: bash-dotfiles
header-args: :mkdirp yes :tangle ~/.config/television/cable/bash-dotfiles.toml
[metadata]
name = "bash-dotfiles"
description = "A channel to select from my bash dotfiles"
requirements = ["bash", "bat", "find", "sort"]

[source]
command = "find $HOME/.bashrc $HOME/.bashrc.d -type f | sort"

[preview]
command = "bat -n --color always --theme auto:system --theme-dark gruvbox-dark --theme-light gruvbox-light '{}'"

Files

CUSTOM_ID: files
header-args: :mkdirp yes :tangle ~/.config/television/cable/files.toml
[metadata]
name = "files"
description = "A channel to select files and directories"
requirements = ["fd", "bat"]

[source]
command = ["fd -t f", "fd -t f -H"]

[preview]
command = "bat -n --color always --theme auto:system --theme-dark gruvbox-dark --theme-light gruvbox-light '{}'"

[keybindings]
shortcut = "f1"

Files With TODO, HACK, etc.

CUSTOM_ID: files-with-todo-hack-etc
header-args: :mkdirp yes :tangle ~/.config/television/cable/todo.toml
[metadata]
name = "todo"
description = "Find TODO, FIXME, HACK, and XXX comments in codebase"
requirements = ["rg", "bat",]

[source]
command = "rg -n --color=always '(TODO|FIXME|HACK|XXX|BUG|WARN):?'"
ansi = true
output = "{strip_ansi|split:\\::..2}"

[preview]
command = "bat -n --color always --theme auto:system --theme-dark gruvbox-dark --theme-light gruvbox-light --highlight-line '{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'"
offset = "{strip_ansi|split:\\::1}"

[keybindings]
enter = "actions:edit"

[ui.preview_panel]
header = "{strip_ansi|split:\\::..2}"

[actions.edit]
description = "Open file in Emacs at the comment"
command = "emacsclient -n '+{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'"
mode = "execute"

Jujutsu Bookmark

CUSTOM_ID: jujutsu-bookmark
header-args: :mkdirp yes :tangle ~/.config/television/cable/jj-bookmark.toml
[metadata]
name = "jj-bookmark"
description = "jujutsu bookmark"
requirements = ["jj",]

[source]
command = "jj bookmark list --color always"
ansi = true
no_sort = true
output = "{strip_ansi|split: :1}"

[preview]
command = "jj show '{strip_ansi|split: :1}'"

Jujutsu Log

CUSTOM_ID: jujutsu-log
header-args: :mkdirp yes :tangle ~/.config/television/cable/jj-log.toml
[metadata]
name = "jj-log"
description = "jujutsu log"
requirements = ["jj",]

[source]
command = "jj log --color always --template builtin_log_oneline --revisions ::@"
ansi = true
no_sort = true
output = "{strip_ansi|split: :2}"

[preview]
command = "jj show '{strip_ansi|split: :2}'"

Theme

CUSTOM_ID: television-theme
header-args: :mkdirp yes :tangle ~/.config/television/themes/default.toml
# general
# background = 'black'
border_fg = 'bright-black'
text_fg = 'bright-blue'
dimmed_text_fg = 'white'
# input
input_text_fg = 'bright-red'
result_count_fg = 'bright-red'
# results
result_name_fg = 'bright-blue'
result_line_number_fg = 'bright-yellow'
result_value_fg = 'white'
selection_fg = 'bright-green'
selection_bg = 'bright-black'
match_fg = 'bright-red'
# preview
preview_title_fg = 'bright-magenta'
# modes
channel_mode_fg = 'black'
channel_mode_bg = 'green'
remote_control_mode_fg = 'black'
remote_control_mode_bg = 'yellow'
send_to_channel_mode_fg = 'cyan'

yamllint

CUSTOM_ID: yamllint
header-args: :mkdirp yes :tangle ~/.config/yamllint/config

See https://yamllint.readthedocs.io/en/stable/configuration.html and https://yamllint.readthedocs.io/en/stable/rules.html.

---

yaml-files:
  - '*.yaml'
  - '*.yml'
  - '.yamllint'

rules:
  braces:
    level: warning
  brackets: enable
  colons:
    level: warning
  commas: enable
  comments:
    level: warning
  comments-indentation:
    level: warning
  document-end: disable
  document-start:
    level: warning
  empty-lines: enable
  empty-values: disable
  float-values: disable
  hyphens: enable
  indentation: enable
  key-duplicates: enable
  key-ordering: disable
  line-length: disable
  new-line-at-end-of-file:
    level: warning
  new-lines: enable
  octal-values: disable
  quoted-strings: disable
  trailing-spaces:
    level: warning
  truthy:
    level: warning

~/.inputrc

CUSTOM_ID: inputrc
header-args: :mkdirp yes :tangle ~/.inputrc
set bell-style none
set colored-completion-prefix on
set colored-stats on
set completion-ignore-case off
set convert-meta off
set expand-tilde on
set input-meta on
set output-meta on
set show-all-if-ambiguous on
set visible-stats on

Footnotes:

1

As of [2025-01-12 Sun] this document is focused on macOS only after I migrated Linux specific configuration to linux.org.

Kris Molendyke

2026-09-25 Fri 14:19

Emacs 31.1 (Org mode 9.8.7)