status-right-length was 451 on a 158-column terminal. tmux lays out the
left segment, then the window list, then gives what is left to the right
segment -- and with the right declared three times wider than the screen
there is no stable allocation. Anything that changes the window list's
rendered width pushes the right segment off entirely, which is why the IP
and clock kept vanishing while the left side stayed put.
The window formats render to 92 characters because of the nested
conditionals that pick a circled number per index, so the list is wide
enough to matter.
This is what the "seizure" was. Not X, not NVIDIA, not picom, not hotplug
events, not the monitors, not mosh, not tmux's version, and not the shell
substitution in status-right -- it reproduced on a bare framebuffer console
with none of those present, and it was intermittent because it depended on
what the window list happened to render at that moment.
Mouse mode routed wheel events into the pane, where Claude Code's
full-screen TUI repaints the whole screen in response. That repaint took
the status bar with it, which is the flicker that has been chased for two
weeks through X, NVIDIA, picom and hotplug settings -- none of which were
involved. It reproduces on a bare framebuffer console with no X running at
all.
Disabling mouse mode keeps those events out of the pane entirely. Scrolling
inside tmux is Ctrl-b [ as usual. Paired with CLAUDE_CODE_DISABLE_MOUSE and
CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL exported in the shell, since the env
block in Claude Code's settings.json does not reach the process.
- tmux-ip: show the first directly-held public/WAN IP on a non-tunnel interface,
else the LAN/private IP. No external 'what's my IP' lookup and no DigitalOcean
special-case (a droplet's eth0 public IP is found by the same interface scan);
RFC1918/link-local/CGNAT classed as not-WAN, so a NAT'd box shows its LAN IP.
- tmux-net: show ✕ when there's no local IP and no VPN tunnel (offline). VPN ⇡
overlay unchanged.
- .tmux.conf: window-status icon + path now native tmux formats (no per-redraw
#() forks); tmux-window-icon kept as fallback.
Pretzo's modules/utility/functions/diff registers an autoload stub that
emits '(eval):1: diff: function definition file not found' in non-
interactive eval contexts where $fpath doesn't include the utility
module's functions directory. Define diff as a real function up front so
the stub never has to look itself up.
Add tmux-vpn-ip helper (parses ifconfig for utun* on macOS, falls back
to tun/wg/ppp on Linux) and a tmux-net wrapper that conditionally
emits "⌂ <local> / ⇡ <vpn>" when a VPN tunnel is up, or just "<local>"
when it's not. status-right now calls tmux-net.
`hostname -I` is GNU-only and errors on BSD/macOS, so when the public-IP
curl couldn't reach api.ipify.org the script printed nothing and the
tmux status bar showed an empty IP. Try `ipconfig getifaddr` for common
interfaces first, fall back to `hostname -I` on Linux, then `ifconfig`
as a last resort. Also guard against empty-but-zero-exit curl output.
STDIN.gets returns nil when stdin is closed/EOF (e.g. after vim/vundle
runs during install), causing `nil.chomp` to abort rake install during
install_term_theme. Return nil from ask() on EOF and have callers bail
out of the iTerm theme prompts gracefully.
The previous snapshot of settings.json was a verbatim dump from one
Mastodon-server install — it carried allowlist entries that won't
match anywhere else and a lot of narrow rules already subsumed by
broader wildcards.
Removed (server-specific, dead weight on other hosts):
- /home/mastodon/* paths and Mastodon .env.production sed/chmod/chown
- signers.online and auto.signers.online curl/openssl probes
- mastodon-web / mastodon-streaming / mastodon-sidekiq journalctl
- n8n journalctl, windmill journalctl + binary
- /usr/local/bin/fail2ban-ignoreip and the hardcoded IP 76.95.82.63
- nslookup signers.live, nginx site-availables grep with literal paths
- /var/log/nginx/access.log* zcat probes (path-specific)
- StatusReactions / status_quoted grep over Mastodon's frontend tree
Removed (redundant, covered by broader wildcard already in the list):
- All narrow Bash(systemctl <verb>:*) entries — Bash(systemctl:*) covers
- All narrow Bash(git ...) entries — Bash(git:*) covers
- All narrow Bash(curl ...) probes — Bash(curl:*) covers
- Bash(rkhunter --update), Bash(rkhunter --propupd) — Bash(rkhunter:*) covers
- Bash(sysctl -a) — Bash(sysctl:*) covers
Kept: tmux/git/curl/sudo/find/ls/cat plus generic system-admin verbs
(systemctl, sysctl, crontab, iptables, ufw, firewall-cmd, fail2ban-client,
apt/apt-get/dpkg, mount, netstat, openssl, lsmod, last, nginx, redis-cli,
rkhunter, aideinit, getent, sqlite3, dig, ulimit, getenforce, aa-status)
plus Read(//home/**), Read(//opt/**), Read(//etc/nginx/sites-{enabled,available}/**).
Net: 5004 -> 1434 bytes (57 lines), still valid JSON, behavior on a
fresh host is identical for the kept verbs and tighter for the dropped
ones (host-specific allows just won't match anything anyway).
If you re-run install.sh on this host, the slim version replaces the
fat one; the fat one survives in ~/.drunkendotfiles.bak.<ts>/ for
recovery.
Saves ~/.claude/settings.json (user-level prefs + Bash/Read permissions
allowlist) so the same Claude Code config can be replicated on other
hosts via install.sh.
What gets deployed:
- .claude/settings.json — theme, verbose, defaultMode, skipAutoPermissionPrompt
and the cumulative "approve once" allowlist for common ops (systemctl,
iptables, journalctl, git, curl, etc.). Server-specific allow entries
(e.g. /home/mastodon/* paths) are dead weight elsewhere but harmless.
- .claude/.gitignore — explicit deny-list so a future `git add .claude`
doesn't accidentally pull in credentials, session logs, project
memories, file-history, telemetry, caches, or settings.local.json.
What is NOT tracked (by design):
- .credentials.json (auth)
- history.jsonl, sessions/, projects/ (chat data, project memories)
- settings.local.json (per-machine overrides — by Claude Code convention)
- file-history/, plans/, paste-cache/, shell-snapshots/, session-env/,
telemetry/, downloads/, cache/, backups/, mcp-needs-auth-cache.json
- plugins/ (marketplace install paths are absolute and host-specific)
deploy_dir's merge semantics mean: on a host that already has
~/.claude/.credentials.json or ~/.claude/projects/, those stay untouched
because the repo doesn't track them. Only the files we explicitly
include get installed.
Existing settings.json on the target host is moved aside to
~/.drunkendotfiles.bak.<timestamp>/ before being replaced.
The committed ~/.local/bin/claude symlink targets a specific Claude Code
version path (whatever was current when this snapshot was taken). On any
host that has Claude Code installed at a different version, that symlink
arrives dangling.
Old behavior: just delete the dangling link and rely on the Claude
installer to recreate it. That doesn't help when the host has Claude
installed but at a version other than the one in the snapshot, and we
also support skipping the installer via DRUNKENDOTFILES_SKIP_CLAUDE=1
(used when the binary is already on disk but at a different version).
New behavior: when the deployed symlink is dangling, scan
~/.local/share/claude/versions/ and repoint the symlink to the highest
installed version (semver sort). Only fall back to deleting the link if
no version is installed at all.
- Switch default-terminal from screen-256color to tmux-256color
(better italics/undercurl/SGR support for nvim, Claude Code, etc.)
- Add terminal-features RGB for the common outer terminals so
truecolor escape sequences pass through cleanly
- Enable focus-events so inner programs can redraw when the pane
regains focus
Identity was previously deferred to ~/.gitconfig.user via the include
at the bottom of this file. Per the dotfiles owner, identity should
travel with the dotfiles regardless of host or local user — every
machine where this repo is deployed commits as dissimulo.
Per-machine bits (safe.directory, etc.) still belong in
~/.gitconfig.user, which the existing [include] at the bottom picks
up after this block.
The Claude Code installer drops the binary at ~/.local/bin/claude.
Without this PATH entry, freshly-installed Claude Code is invisible to
new shells until the user adds it manually. Other ~/.local/bin scripts
in this dotfiles repo (tmux-ip, tmux-window-icon, twitterbot, etc.)
benefit from the same.
YADR's Rakefile maps tmux/tmux.conf -> $HOME/.tmux.conf, but the
canonical, customized tmux config has lived at the repo root since
3d2508a (when the relationship was inverted). Re-running rake install
on its own (without the bash installer's subsequent personal-deploy
overlay) was therefore replacing the deployed real .tmux.conf with a
symlink to the older 3987-byte tmux/tmux.conf, dropping the IP/host
status-right and the bumped history limit.
Pointing tmux/tmux.conf at ../.tmux.conf via a relative symlink fixes
this on any machine, regardless of where ~/.yadr lives or which user
owns it: rake install's symlink chain now resolves to the customized
config no matter the install order.
The previous `[include] path = .gitconfig.user` was resolved relative to
the config file being read, which — because `~/.gitconfig` is a symlink
to `~/.yadr/git/gitconfig` — meant git looked for the user-identity
override at `~/.yadr/git/.gitconfig.user` instead of the conventional
`~/.gitconfig.user`. Switch to an absolute path so the include picks up
the homedir file regardless of symlink layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous deploy_one() did `mv $HOME/<dir> $BACKUP_DIR/<dir>` then
`cp -a $YADR_DIR/<dir> $HOME/<dir>` for every entry in PERSONAL_DIRS.
For dirs the repo only partially populates (notably .local — repo only
tracks .local/bin/), this swept away unrelated user data: the most
recent re-bootstrap moved ~/.local/share/fonts/ (Intel One Mono, Open
Gorton, Roboto Mono, GALLAUDET, code128) into the timestamped backup,
making them appear missing.
Rework deploy logic:
- deploy_file: copies one file/symlink, backing up only the conflicting
destination (if any). Idempotent via paths_equivalent() so re-runs
with no changes produce no output and no spurious backups.
- deploy_dir: walks the repo's tree for that dir and deploys each leaf
via deploy_file. Files in $HOME the repo doesn't know about are left
untouched. Subdirs are mkdir'd as needed.
Also: track the personal fonts at .local/share/fonts/ so they redeploy
on every install, and run fc-cache -f at the end so apps see them
without a logout/login.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
~/ascii is a symlink to ~/.yadr/ascii. Without -L, 'find <symlink>'
treats the link itself as the starting point, -type f rules it out,
and fuzzy matches return nothing.
New .local/bin/spam-ascii POSIX shell script: resolves a pattern to
a file in ~/ascii with this order:
1. exact filename match
2. exact name + common ASCII-art extension (.txt/.ans/.asc)
3. first case-insensitive substring match (sorted alphabetically)
Non-zero exit + stderr-ish error if nothing matches, so /spam
prints 'no match in ~/ascii for: <pattern>' instead of spewing
a missing-file error.
Rewire the irssi /spam alias to call the script instead of
hardcoding 'cat ~/ascii/$0'. Now:
/spam mario -> matches ~/ascii/mario.txt or ~/ascii/Mario_art.ans
/spam MARIO -> case-insensitive
/spam nothere -> 'no match in ~/ascii for: nothere'
/spam <name> runs 'cat ~/ascii/<name>' via EXEC -out, which sends
each line of output as a message to the current channel/query. Good
for posting ASCII art.
Usage: /spam <filename> (file lives at ~/ascii/<filename>)
- rainbow-dark.theme: revert line_start back to the stock '-!-' pattern.
- .irssi/scripts/autorun/rainbow-timestamp.pl: new autorun script that
hooks 'print text', matches a leading HH:MM[:SS], and reruns it
through rainbow.pl's make_colors (same palette [4,8,9,11,12,13],
same 2-char stride, same phase-advance on each line). The result
is that every successive timestamp is a 5-character rainbow
gradient that also shifts starting colour line-to-line.
claude.theme: a dark irssi theme whose colours map 1:1 to the roles
Claude Code uses in its default dark UI:
#8c8c8c dim timestamps, brackets, connective text
#f85149 red errors, netsplits, parts, private msg frames
#56d364 green joins, ctcp, dcc, netjoins, quiet activity
#e3b341 yellow messages-to-me, /me, statusbar chatter
#4a9eff blue channel names, pubnicks, diff-style accents
#c9a3ff magenta own nick / prompt / notices / hilights
#4ec9b0 cyan whois field names, info lines
Uses 24-bit true-colour escapes (%z<rrggbb>) so the shades land
exactly regardless of terminal palette. Requires irssi 1.2+ and a
truecolour-capable terminal (modern xterm/tmux both are).
irssi/config: switch the active theme from rainbow-dark to claude.
Autorun script so the same drunkendotfiles deploy gives each host a
distinctive nick without per-host config hand-edits. Trims FQDNs to
the short hostname before composing. Static 'nick = "`"' in
config stays as a fallback if the script ever fails to load.
R-Y-G-C-B-M was only six. Full spectrum now: red, orange (%y dark
yellow, renders brown-orange on most terminals), yellow, green,
blue, indigo (%b dark blue as the closest ANSI indigo), violet
(%M bright magenta). Stays ANSI-only so it renders reliably
regardless of 24-bit truecolor support.
Scrap the over-engineered version. Start from irssi's default theme
(already dark-safe) and apply rainbow only where it actually earns
its keep:
- line_start: the leading '-!-' on non-message lines gets a full
R-Y-G-C-B-M dash sequence instead of blue-blue.
- sb_act_msg: drop the %W (white) on statusbar activity — on a dark
terminal this was the one stark-white glyph. Re-colour the whole
activity band as a rainbow escalation: %G (quiet) -> %Y (chatter)
-> %R (hilight), so urgency tracks the colour.
- sb_act_sep: comma separator drops to %K (dark grey) so the rainbow
entries stand apart.
Everything else stays untouched from default.theme. No invented
24-bit escapes, no format overrides.
Previous commit used %Z005f5f, which irssi 1.4 interprets as a
24-bit *background* colour. That rendered as 'teal background
behind each affected character' — easy to miss on short glyphs,
invisible on whitespace. Foreground is %z (lowercase).
Earlier pass tried %X17 (256-palette idx 23), but %X isn't the
256-colour code in modern irssi — 1.4+ treats %X as a no-op for
unknown sequences, so every intended teal element was silently
falling through to the terminal default (= bright white).
irssi 1.4.5 supports %Z<rrggbb> for 24-bit foreground colour, so
use it directly: %Z005f5f renders as exactly #005f5f (dark teal),
no palette guessing.
Every %K (dark grey / bright-black) swapped for %X17 — 256-colour
foreground 0x17 == palette index 23, RGB #005f5f, a very dark
teal/cyan. Applies to: body text, bracket/punctuation replaces,
message-body dim, connective text in join/part/quit/etc. formats,
dccfile name, whois values, servernotice body, wallop body.
Requires a 256-colour-capable terminal; irssi renders %X17 as
palette 23 when the terminal advertises 256 colour support (most
modern terminals do — .tmux.conf already sets TERM=screen-256color).
- Body text color bumped from %w (light grey, sometimes renders ~white)
to %K (dark grey / 'bright black'), affecting msgnick and all action
templates.
- Statusbar / info bg changed from %8 (terminal default, which some
terminals render as reverse-video white) to explicit %0 (black) so
the bar is reliably dark everywhere.
- Added color to spots that were falling through to terminal default:
whois values, servernotice body, wallop_nick, wallop_action body,
dccfile.
- Expanded 'fe-common/core' formats block to override joins, parts,
quits, kicks, nick/topic/mode changes, aways etc. — coloured nicks
via the existing abstracts but the surrounding 'has joined' /
'changed the topic' verbiage now renders in dim grey instead of
stark white.
rainbow-dark.theme:
- Message body text now tinted dim grey (%w) instead of inheriting
terminal-default (usually stark white) — done via a trailing %w in
the msgnick template.
- Own nick in public, private, and DCC contexts switches from bold
white (%W) to bold bright magenta (%M) so 'you' stays distinct but
stops looking like every other bright-white element.
- Action bodies (public, private, DCC) get the same %w dim-grey tint.
.irssi/config: add W1..W99 aliases so /w1, /w2, ... /w99 jump
directly to that window (pair to the existing bare numeric /1 /2
aliases, for users whose muscle memory has 'w' in it).
The skwp prompt's precmd calls git-info and ruby-info (prezto module
functions that live in ~/.zprezto/modules/{git,ruby}/functions). On
interactive shell startup, something — likely compinit's
insecure-directory pruning when parent dirs are group-writable —
strips those paths from $fpath after pmodload seeded them.
When precmd then references the autoload-declared-but-unfindable
functions, zsh fails to locate the definition file, aborts the
prompt render midway through, and zsh-syntax-highlighting latches
onto the broken half-prompt. Observed symptoms:
prompt_skwp_precmd: git-info: function definition file not found
prompt_skwp_precmd: ruby-info: function definition file not found
zsh: bad math expression: operand expected at '%F{135}%n%...'
_zsh_highlight_call_widget:2: bad math expression: operand...
Defensive re-seed: before calling 'prompt skwp', prepend the helper,
git, and ruby module function dirs to $fpath if they aren't already
present. Idempotent, cheap, and masks any upstream stripping
regardless of cause.
Adds a step after personal-dotfile deploy that runs Anthropic's
official one-liner installer (curl -fsSL https://claude.ai/install.sh | bash)
when no 'claude' binary is found. No-ops if claude is already on the
machine. Opt out with DRUNKENDOTFILES_SKIP_CLAUDE=1. Install failures
are non-fatal — the rest of the flow still completes.
README: document the new step + the opt-out env var + curl in the
required tools list.
install.sh: use --recurse-submodules on the initial clone, and always
run 'git submodule update --init --recursive' before rake install so a
fresh checkout doesn't leave zsh/prezto empty.
README: document --recurse-submodules for manual clones; mention the
recovery command for existing shallow clones.
Fixes: bad math expression errors and 'no such file or directory:
~/.zprezto/runcoms/zshrc' on fresh shell startup when the Prezto
submodule hadn't been initialized.
The DigitalOcean metadata endpoint for reserved/floating IPv4 is
/metadata/v1/{reserved,floating}_ip/ipv4/ip_address, not .../address.
The .../active check works but the wrong IP path returned an empty
body, causing the script to silently fall through to ipify on every
droplet with a reserved/floating IP attached.
Verified on a droplet:
curl .../reserved_ip/ipv4/ip_address -> 45.55.111.240
curl .../reserved_ip/ipv4/address -> (empty)
If /sys/class/dmi/id/sys_vendor says DigitalOcean and the droplet has
a reserved_ip or floating_ip assigned, use that over the ipify-based
egress IP. Keeps the ipify/hostname -I fallback intact for other hosts.
Gated on the DMI check so non-DO hosts skip the metadata probe entirely
and the tmux status bar refresh stays fast.
install.sh: curl-pipe installer that clones to ~/.yadr, runs YADR's
native rake install, then layers personal dotfiles on top of $HOME
with backups on collision.
README.md: replace YADR's upstream readme with drunkendotfiles-
specific usage docs, credit, and refresh-from-upstream instructions.
- Convert 21 absolute-path symlinks into YADR to relative paths
(e.g. .vimrc -> .yadr/vimrc), so they resolve correctly under
any user's $HOME after a standard YADR install.
- .fehbg: replace hardcoded background path with $HOME-based one
- .gtk-bookmarks: remove (trivially personal; GTK regenerates)
- .themes/*/index.theme: drop BackgroundImage= lines pointing at
personal image files that other users won't have.
- .xscreensaver: scrub username from header comment.
- .irssi/config: generic dcc_download_path.
Tracks shell configs (zsh/bash), vim, tmux, irssi, fonts, themes,
and ~/.local/bin scripts. Sensitive files (.ssh, .gnupg, history,
credentials) and large app data are excluded via .gitignore.