dotfiles: add beets, sync-music script, firstmate, ngrok, openssh, gh/tmux/treehouse/opencode/pi brews

This commit is contained in:
Lap Tran
2026-08-08 21:20:27 -04:00
parent 6eee2509a4
commit 4a0bff0331
9 changed files with 326 additions and 36 deletions
+127 -22
View File
@@ -1,7 +1,9 @@
{ config, pkgs, ... }:
{ config, pkgs, lib, ... }:
let
dotfiles = "${config.home.homeDirectory}/.dotfiles";
home = config.home.homeDirectory;
dotfiles = "${home}/.dotfiles";
firstmateHome = "${home}/Documents/firstmate";
in
{
@@ -16,10 +18,12 @@ in
lazygit
neovim
nerd-fonts.hack
ngrok # reverse TCP tunnel so the phone can SSH in over cellular (unfree)
beets # music tagger / library organizer + navidrome sync plugin
];
fonts.fontconfig.enable = true;
home.sessionVariables.EDITOR = "nvim";
programs.zsh = {
enable = true;
autosuggestion.enable = true; # ghost text from history
@@ -38,6 +42,14 @@ in
cc = "claude --dangerously-skip-permissions";
co = "codex --full-auto";
gb = "grok --yolo";
# firstmate primary session via Pi (approve project trust once per clone)
fm = "cd ${firstmateHome} && exec pi";
# Sync ~/Music into the beets library on Unraid (requires NAS mounted).
sync-music = "~/.local/bin/sync-music";
# Start the reverse tunnel so you can SSH into this Mac from your phone.
# Run once when you go remote: `ngrok-tunnel`. Reads authtoken from
# ~/.config/ngrok (set once per machine with `ngrok config add-authtoken <TOK>`)
ngrok-tunnel = "ngrok tcp 22";
};
};
@@ -54,29 +66,122 @@ in
};
};
# Edit-in-place: the real file stays in my repo, the live path just points at it.
home.file.".config/wezterm".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/wezterm";
home.file.".config/nvim".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/nvim";
home.file.".config/herdr".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/herdr";
# Edit-in-place: real file stays in the repo; live path is an out-of-store symlink.
# force = true: replace a pre-existing regular file once; source of truth is home/.
home.file.".config/wezterm" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/wezterm";
force = true;
};
home.file.".config/nvim" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/nvim";
force = true;
};
home.file.".config/herdr" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/herdr";
force = true;
};
# Beets music library manager - managed by nixpkgs package, config symlinked below.
home.file.".config/beets" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.config/beets";
force = true;
};
# Claude Code settings (also read by Grok for permissions/compat)
home.file.".claude/settings.json".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.claude/settings.json";
home.file.".claude/settings.json" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.claude/settings.json";
force = true;
};
# Shared agent policy - one file, many harnesses
home.file.".claude/CLAUDE.md".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
home.file.".codex/AGENTS.md".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
home.file.".config/opencode/AGENTS.md".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
home.file.".grok/AGENTS.md".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
home.file.".claude/CLAUDE.md" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
force = true;
};
home.file.".codex/AGENTS.md" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
force = true;
};
home.file.".config/opencode/AGENTS.md" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
force = true;
};
home.file.".grok/AGENTS.md" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
force = true;
};
# Grok Build native config
home.file.".grok/config.toml".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.grok/config.toml";
home.file.".grok/config.toml" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.grok/config.toml";
force = true;
};
# Pi agent - source of truth under home/.pi (sessions/auth/npm stay live under ~/.pi)
home.file.".pi/agent/settings.json" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.pi/agent/settings.json";
force = true;
};
home.file.".pi/agent/models.json" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.pi/agent/models.json";
force = true;
};
home.file.".pi/agent/themes" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.pi/agent/themes";
force = true;
};
home.file.".pi/agent/extensions/terminal-status-title.js" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.pi/agent/extensions/terminal-status-title.js";
force = true;
};
home.file.".pi/agent/extensions/calm" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/.pi/agent/extensions/calm";
force = true;
};
home.file.".pi/agent/AGENTS.md" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfiles}/home/AGENTS.md";
force = true;
};
# firstmate is a mutable agent distro (self-update, state/, projects/). Clone once;
# never put it in the Nix store. Seed Pi+herdr defaults only when absent.
# Do NOT npm install -g here: activation PATH often resolves Nix's npm, which
# cannot write into the store (EACCES). Use Homebrew's node for globals:
# /opt/homebrew/bin/npm install -g tasks-axi quota-axi no-mistakes gh-axi lavish-axi chrome-devtools-axi
home.activation.firstmate = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
set -euo pipefail
fm="${firstmateHome}"
git="${pkgs.git}/bin/git"
if [ ! -d "$fm/.git" ]; then
mkdir -p "$(dirname "$fm")"
$git clone https://github.com/kunchenguid/firstmate.git "$fm"
fi
mkdir -p "$fm/config" "$fm/data" "$fm/state" "$fm/projects"
# Local gitignored operating choices (do not overwrite captain edits)
[ -f "$fm/config/backend" ] || printf 'herdr\n' > "$fm/config/backend"
[ -f "$fm/config/crew-harness" ] || printf 'pi\n' > "$fm/config/crew-harness"
'';
# Authorize the SSH key so the phone can log in through the ngrok tunnel.
# (home-manager 26.05 removed programs.ssh.authorizedKeys; manage the file
# here so ~/.ssh is 0700 and authorized_keys is 0600. Public key is not a secret.)
home.activation.authorizeSSHKey = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
set -euo pipefail
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
printf '%s\n' "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGCZEGVYMDztSryFwoZ6cfpBH3ksP3h0yxZSanlcbrZ0 unraid-omada" > "$HOME/.ssh/authorized_keys"
chmod 600 "$HOME/.ssh/authorized_keys"
'';
# Wire the sync-music script into ~/.local/bin without touching anything else
# that lives there (node, python3.11, hermes, etc.). Source of truth is the
# dotfiles repo so a rebuild restores it if it ever disappears.
home.activation.syncMusic = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
set -euo pipefail
ln -sfn "${dotfiles}/home/bin/sync-music" "$HOME/.local/bin/sync-music"
'';
}