Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,14 @@ home/dot_config/cliamp/cliamp.sock
home/dot_config/cliamp/cliamp.sock.pid
home/dot_config/cliamp/history.toml
home/dot_config/cliamp/resume.json

# Font binaries never enter this repo (2026-09-17). The Anthropic faces are
# unlicensed brand trade dress and live only on the NAS M.2; pkgs/fontbuilder
# is the press and ships no bytes. nerd-font-patcher writes its output into the
# CURRENT DIRECTORY under some flags (`--cell '?'` does not query, it patches),
# which is how a 440 KB patched TTF once landed in this repo root.
*.ttf
*.otf
*.woff
*.woff2
*.tar.zst
265 changes: 265 additions & 0 deletions docs/fonts/README.md

Large diffs are not rendered by default.

1,212 changes: 1,212 additions & 0 deletions docs/fonts/anthropic-suite.md

Large diffs are not rendered by default.

456 changes: 456 additions & 0 deletions docs/fonts/nas-and-bootstrap.md

Large diffs are not rendered by default.

38 changes: 32 additions & 6 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,15 @@
# SF Pro itself stays (2026-08-21 ruling: "it's too good to have") but is
# now pkgs/sf-pro.nix, pinned by sha256 to the fleet's own copy.
#
# ALL APPLE FONTS LIVE ON THE NAS M.2 (Tom, 2026-09-15: "i do not want to
# download the fonts again everytime i do an update"; "keep the fonts on
# the m2 ssd"): nas:/mnt/fast/fonts/apple/, one tarball per family, exact
# bytes installed that day, requireFile-pinned — no flake input, no
# download. home/update-center-seed.nix seeds them into the NAS store.
# Do not re-add a URL-locked font input.
# ALL VENDOR FONT BYTES LIVE ON THE NAS M.2 (Tom, 2026-09-15: "i do not
# want to download the fonts again everytime i do an update"; "keep the
# fonts on the m2 ssd"): nas:/mnt/fast/fonts/<vendor>/ — apple/ since
# 2026-09-15, anthropic/ since 2026-09-17 — one tarball per package, exact
# bytes installed that day, requireFile-pinned: no flake input, no
# download, and no font binary in this repo (see .gitignore).
# home/update-center-seed.nix seeds them into the NAS store. The press that
# produced the anthropic/ tarballs is pkgs/fontbuilder, which ships the
# recipe and no bytes. Do not re-add a URL-locked font input.
#
# TOMBSTONE — sfmono-liga input (shaunsingh/SFMono-Nerd-Font-Ligaturized),
# removed 2026-09-15 under the rule above; pkgs/sfmono-liga.nix. Liga SF
Expand All @@ -101,6 +104,17 @@
# Tom, on seeing real Maple: "i like whatever font was in use before
# this afternoon's pushes." kitty.conf now names this family
# EXPLICITLY, so no future sweep can silently swap the terminal again.
#
# 2026-09-17: the terminal face moved to `AnthropicMono Nerd Font Mono`
# (pkgs/anthropic-mono-nerd.nix, pressed by pkgs/fontbuilder). Deliberate,
# with the family named explicitly in kitty.conf AND verified through
# kitty's OWN resolver (`kitty +runpy` -> get_font_files), which is the
# check the 2026-08-21 incident lacked: fc-scan alone would not have caught
# it, because kitty does not consult fontconfig for an exact-name hit and
# falls through to fc_match SILENTLY when it misses. sfmono-liga and sf-pro
# remain INSTALLED and are the revert path — a four-line kitty.conf edit
# plus a switch. A future sweep that removes either of them kills that
# revert; do not remove them without replacing the revert plan.

# git-ai — AI-authorship tracking CLI (github.com/git-ai-project/git-ai).
# Consume its flake package directly and pin it in flake.lock. The Home
Expand Down Expand Up @@ -446,6 +460,10 @@
llm-agents = inputs.llm-agents.packages.${system};
sfmono-liga = final.callPackage ./pkgs/sfmono-liga.nix { };
sf-pro = final.callPackage ./pkgs/sf-pro.nix { };
anthropic-mono-nerd = final.callPackage ./pkgs/anthropic-mono-nerd.nix { };
anthropic-ui = final.callPackage ./pkgs/anthropic-ui.nix { };
anthropic-webfonts = final.callPackage ./pkgs/anthropic-webfonts.nix { };
fontbuilder = final.callPackage ./pkgs/fontbuilder { };
})
# Pin-decoupled "hot" packages — see the nixpkgs-fresh input comment above.
# Cherry-picked, not a wholesale pkgs swap: only packages named here track
Expand Down Expand Up @@ -653,6 +671,14 @@
crm
dcal
fleet-status
# `nix run .#fontbuilder -- <capture-dir> <out-dir>` — the press for
# the Anthropic suite. Exported because that IS the invocation. The
# three anthropic-* font packages stay UNEXPORTED (matching sf-pro):
# nothing needs to `nix build` a requireFile derivation by name, and
# exporting them only gives `nix flake check` more ways to trip over
# a tarball that is not in this machine's store. To build one anyway:
# nix build --impure --expr '(builtins.getFlake "'"$DOT"'").nixosConfigurations.coordinator.pkgs.anthropic-mono-nerd'
fontbuilder
local-ai-monthly
# `nix build .#local-models-prune` — the ONLY verb on this fleet
# that deletes a working copy. Exposed so the guard suite can be
Expand Down
61 changes: 57 additions & 4 deletions home/dot_config/kitty/kitty.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,68 @@ shell fish
# whatever font was in use before this afternoon's pushes"). Proven from the
# live kitty's /proc maps during the 2026-08-21 font-sweep incident. Bold is
# SemiBold on purpose: that is the weight the fallback actually served.
font_family Liga SFMono Nerd Font
bold_font Liga SFMono Nerd Font SemiBold
italic_font Liga SFMono Nerd Font Italic
bold_italic_font Liga SFMono Nerd Font SemiBold Italic
# --- previous face (2026-08-21 .. 2026-09-17), kept for the two-file revert ---
# font_family Liga SFMono Nerd Font
# bold_font Liga SFMono Nerd Font SemiBold
# italic_font Liga SFMono Nerd Font Italic
# bold_italic_font Liga SFMono Nerd Font SemiBold Italic
# --- end previous face ---
#
# 2026-09-17: the terminal face is AnthropicMono Nerd Font Mono, pressed by
# pkgs/fontbuilder and pinned to the NAS M.2 (pkgs/anthropic-mono-nerd.nix).
#
# kitty does NOT split "family style" strings. find_best_match()
# (kitty/fonts/fontconfig.py:180-221) looks the string up VERBATIM in the
# nameID6 / nameID4 / nameID1+16 maps, then falls through to fc_match SILENTLY.
# nerd-font-patcher --makegroups 4 caps nameID4 at 31 chars, so this face's
# nameID4 is the ABBREVIATED "AnthropicMono NFM SemiBold" (26); the long form
# (37) is not a key and never will be. Measured 2026-09-17:
# "AnthropicMono Nerd Font Mono SemiBold"
# before the defaultFonts commit -> LigaSFMonoNerdFont-SemiBold
# (WRONG FAMILY, right weight)
# after the defaultFonts commit -> AnthropicMonoNFM (right family,
# WEIGHT SILENTLY DROPPED)
# "AnthropicMono NFM SemiBold" -> AnthropicMonoNFM-SemiBold (ok, exact nameID4)
# family="..." style="SemiBold" -> AnthropicMonoNFM-SemiBold (ok, used here)
# family=/style= is used because it is the only form whose result does not
# depend on the monospace alias or on nameID4 surviving a patcher release.
# Verified through kitty's OWN resolver (kitty +runpy -> get_font_files), and
# proven from the review window's /proc maps before this block landed.
#
# The style STRING is matched exactly (lowercased). A typo empties the candidate
# list and kitty falls silently to fc-match: measured, style="Semi Bold" ->
# AnthropicMonoNFM-Bold. SemiBold / Italic / SemiBold Italic are literals.
#
# Bold stays SemiBold (2026-08-21 ruling); kitty's own `auto` picks SemiBold too.
#
# REVERT IS TWO FILES. After the defaultFonts commit,
# "Liga SFMono Nerd Font SemiBold Italic" resolves into the Anthropic family,
# so reverting this file alone gives the WRONG FAMILY for every non-exact line.
# Revert modules/common.nix defaultFonts AND this block, together.
#
# Geometry vs Liga SFMono at font_size 16.0, measured with kitty's own
# create_test_font_group: cell 13x27 px @96dpi and 26x54 @192dpi, against Liga
# SFMono's 13x26 and 26x51. COLUMN WIDTH IS IDENTICAL at this size (0.600 em =
# 25.6 px and 0.6182 em = 26.4 px both round to 26 at scale 2), so the column
# count does NOT change; only the rows do, by -3.70% @96dpi and -5.56% @192dpi.
# x-height 0.5400 em vs 0.5298, cap 0.7200 vs 0.7046.
# `modify_font cell_height -6%` takes 54 px back to 51 px (Liga SFMono's density
# at scale 2). Left unset on purpose.
font_family family="AnthropicMono Nerd Font Mono"
bold_font family="AnthropicMono Nerd Font Mono" style="SemiBold"
italic_font family="AnthropicMono Nerd Font Mono" style="Italic"
bold_italic_font family="AnthropicMono Nerd Font Mono" style="SemiBold Italic"
# 16.0 (2026-09-16): Tom pressed ctrl+= once in every new kitty. That binding
# is the legacy `increase_font_size`, which in kitty 0.48.0 (boss.py) is a
# fixed +2.0pt step, so 14.0 + one press = 16.0 — now the starting size.
font_size 16.0
disable_ligatures never
# symbol_map is deliberately EMPTY. kitty draws U+2500-259F, U+2800-U+28FF
# (braille), powerline and legacy-computing cells ITSELF (kitty/fonts.c
# font_for_cell -> BOX_FONT) before symbol_map is consulted; and a symbol_map
# range is a HARD map - kitty does not check whether the mapped face has the
# codepoint and does not fall through, so mapping CJK/Kana/Hangul to a face that
# lacks them replaces working Noto CJK with notdef boxes (measured 2026-09-17).

# Cursor
cursor_blink_interval 0
Expand Down
41 changes: 38 additions & 3 deletions home/home.nix
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,14 @@ in
# (the one Apple family kept in the 2026-08-21 sweep — "too good to
# have"); before this key was set at all, GTK fell back to Adwaita Sans —
# the "odd Nautilus font" on first boot.
font-name = "SF Pro Display 11";
document-font-name = "Adwaita Sans 12";
monospace-font-name = "Adwaita Mono 11";
# 2026-09-17: the Anthropic suite. All three keys move together so the
# desktop is consistent on day one; sizes preserved so no GTK app changes
# metrics. sf-pro stays installed and reachable by name.
# fc-match "Anthropic Sans" returns the file's default instance (opsz 16 =
# the Text cut), the right optical size for an 11 pt UI.
font-name = "Anthropic Sans 11";
document-font-name = "Anthropic Serif 12";
monospace-font-name = "AnthropicMono Nerd Font Mono 11";
};

# bin/ scripts: whole-dir (the repo owns ~/.local/bin).
Expand All @@ -310,6 +315,14 @@ in
# wallpapers — whole-dir at ~/.local/share/wallpapers (wallpaper.jpg + placeholder).
home.file.".local/share/wallpapers".source = link "dot_local/share/wallpapers";

# One stable $HOME path the docs can name for the Anthropic woff2 + CSS, since
# the real one is the profile path /etc/profiles/per-user/tom/share/webfonts.
# Measured safe 2026-09-17: fontconfig's only xdg directory is
# `<dir prefix="xdg">fonts</dir>` (/etc/fonts/fonts.conf:104), i.e.
# ~/.local/share/fonts EXACTLY — so a sibling named `webfonts` is not scanned.
# DO NOT rename this to `fonts`.
home.file.".local/share/webfonts".source = "${pkgs.anthropic-webfonts}/share/webfonts";

# bash login files. dot_bashrc sources ~/.env (secrets) — harmless missing-file
# warning until that file exists.
home.file.".bashrc".source = link "dot_bashrc";
Expand Down Expand Up @@ -506,6 +519,28 @@ in
# browser
google-chrome

# Anthropic woff2 + the @font-face sheet. Installed path is
# /etc/profiles/per-user/tom/share/webfonts/{woff2,css} — NOT
# ~/.nix-profile/share/webfonts. flake.nix sets
# home-manager.useUserPackages = true (with useGlobalPkgs = true), which
# routes home.packages through users.users.tom.packages; home-manager
# creates no ~/.nix-profile at all, and the one that exists on this box is
# an unrelated imperative `nix profile` holding only brave. Verified
# 2026-09-17 on five packages already in this list (eza, zoxide, glow,
# bat, fd): all five resolve under /etc/profiles/per-user/tom/bin and
# none under ~/.nix-profile/bin. Do not "correct" this back.
#
# NOT in fonts.packages: see the comment in modules/common.nix.
# home-manager's generated ~/.config/fontconfig/conf.d/10-hm-fonts.conf
# adds only <profile>/share/fonts and <profile>/lib/X11/fonts, so
# share/webfonts is never indexed and cannot contend with the installed
# TTFs (re-verified against the built package: 13 fc-list rows, all from
# the control TTF, zero woff2; adding share/webfonts yields 15 extra
# woff2 rows). This entry is also the only thing that pulls the
# derivation into a host closure, so attic caches it and the nightly
# builds it.
anthropic-webfonts

# fish init + shell
eza
zoxide
Expand Down
82 changes: 72 additions & 10 deletions home/update-center-seed.nix
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,60 @@
# window, and the NAS names any gap itself: update-center's preflight logs
# `seed-missing <node>` for every private node whose tree is absent.
#
# FONTS (2026-09-15). pkgs/sf-pro.nix and pkgs/sfmono-liga.nix pin every Apple
# face to the fleet's own tarballs on the NAS M.2 (nas:/mnt/fast/fonts/apple),
# never a download. The same run has the NAS add each tarball to its own store
# straight from that disk and root it here beside the source trees, so the
# nightly build finds them.
# FONTS (2026-09-15, extended 2026-09-17). pkgs/sf-pro.nix, pkgs/sfmono-liga.nix,
# pkgs/anthropic-mono-nerd.nix, pkgs/anthropic-ui.nix and
# pkgs/anthropic-webfonts.nix pin every vendor face to the fleet's own tarballs
# on the NAS M.2 (nas:/mnt/fast/fonts/{apple,anthropic}), never a download. The
# same run has the NAS add each tarball to its own store straight from that disk
# and root it here beside the source trees, so the nightly build finds them.
let
isCoordinator = osConfig.networking.hostName == "coordinator";
# Full paths, not bare names: since 2026-09-17 there is a second vendor
# directory on the M.2 (anthropic/ beside apple/). The GC-root name is the
# BASENAME stripped at the FIRST dot, so every basename must stay dot-free
# before ".tar.zst" AND unique across directories — /var/lib/update-center/
# seeds is one flat namespace shared with the locked flake nodes (tally,
# tally-b, tally-lake) and the cleanup sweep below does not descend.
#
# Two failure modes. (1) A colliding basename silently clobbers the other
# vendor's GC root, and the loss is discovered on the NAS at 01:30. This is
# the one fontRootNames catches at EVAL time — but only font-vs-font; the
# locked node names are discovered at RUNTIME from the lock and are invisible
# here, so font-vs-node is checked in the shell instead (see the pairs loop).
# (2) Without the basename strip, ''${f%%.*} on a PATH yields an ABSOLUTE name,
# so `nix-store --realise --add-root "$d/$name"` targets a nonexistent
# directory and fails. The remote body runs under `set -eu`, so the script
# aborts THERE and the sweep below never runs: the failure is loud (the unit
# fails, failure-surfacing sees it) and no existing root is touched.
# Measured 2026-09-17.
# Keep the strip anyway: a loud nightly failure is still a broken seed.
fontArchives = [
"sf-pro-fonts.tar.zst"
"sfmono-liga-fonts.tar.zst"
"/mnt/fast/fonts/apple/sf-pro-fonts.tar.zst"
"/mnt/fast/fonts/apple/sfmono-liga-fonts.tar.zst"
"/mnt/fast/fonts/anthropic/anthropic-mono-nerd-fonts.tar.zst"
"/mnt/fast/fonts/anthropic/anthropic-ui-fonts.tar.zst"
"/mnt/fast/fonts/anthropic/anthropic-webfonts.tar.zst"
];
# An INDEPENDENT second implementation of the shell's ''${f##*/} + ''${b%%.*}
# below; nothing ties the two together, so change them as a pair.
fontRootNames = map (p: lib.head (lib.splitString "." (baseNameOf p))) fontArchives;
fontRootNamesCollide = lib.length (lib.unique fontRootNames) != lib.length fontRootNames;
fontRootNameEmpty = lib.any (n: n == "") fontRootNames;
# In the second guard below, only `n == ""` can ever fire, and only for a
# basename beginning with a dot: `baseNameOf` cannot return a string
# containing "/", so a `lib.hasInfix "/" n` disjunct would be dead code (it
# was in the first draft). One case still slips through both guards and is
# accepted: a path with a TRAILING slash, for which baseNameOf returns the
# parent directory name (baseNameOf "/mnt/fast/fonts/anthropic/" ->
# "anthropic"). The message wording is the documented contract; leave it.
checkedFontArchives =
lib.throwIf fontRootNamesCollide
"update-center-seed: font archive basenames collide once stripped at the first dot: ${toString fontRootNames}"
(
lib.throwIf fontRootNameEmpty
"update-center-seed: a font archive basename yields an empty or nested GC-root name"
fontArchives
);

seed = pkgs.writeShellApplication {
name = "update-center-seed";
Expand Down Expand Up @@ -111,13 +154,32 @@ let
# Root each seed by node name, then drop names this lock no longer has.
# Arguments are name=path pairs; node names and store paths carry no
# shell metacharacters, and the remote body is a quoted heredoc. A font
# pair names a file on the NAS M.2 instead, which is added there first.
# pair names a file on the NAS M.2 instead, which is added there first;
# its GC-root name is the BASENAME up to the first dot, so the directory
# in the value is what distinguishes apple/ from anthropic/.
pairs=()
for i in "''${!paths[@]}"; do
pairs+=("''${names[$i]}=''${paths[$i]}")
done
for f in ${lib.escapeShellArgs fontArchives}; do
pairs+=("''${f%%.*}=/mnt/fast/fonts/apple/$f")
# The eval-time lib.throwIf above covers font-vs-font name collisions.
# This covers font-vs-NODE, which it cannot: the locked node names come
# from the lock at RUNTIME. Measured 2026-09-17 — a font archive named
# tally.tar.zst evaluates cleanly and the unmodified remote heredoc then
# silently CLOBBERS seeds/tally with the tarball (keep contains "tally",
# so the sweep preserves the wrong one), surfacing only as update-center's
# `seed-missing tally` on the NAS at 01:30. Fail here instead.
for f in ${lib.escapeShellArgs checkedFontArchives}; do
b="''${f##*/}"
n="''${b%%.*}"
# ''${names[@]+...} keeps this safe under `set -u` when the lock names
# no mecattaf node at all.
for m in ''${names[@]+"''${names[@]}"}; do
if [ "$m" = "$n" ]; then
log "FAILED: font archive $b would take the GC-root name '$n', already claimed by locked node $m" >&2
exit 1
fi
done
pairs+=("$n=$f")
done
sshnas bash -s -- "''${pairs[@]}" <<'REMOTE'
set -eu
Expand Down
Loading