refactor: fix yolo config drift and restart traps
CI / lint (push) Successful in 32s
CI / eval (push) Successful in 2m7s

yolo's .claude/settings.json was a full fork of the common file, not the
narrow override its comment claimed: sandbox, defaultMode, voiceEnabled,
$schema and feedbackSurveyState were absent, and five more keys had
diverged. It now holds only yolo's overrides and merges over common via
recursiveUpdate. sandbox.enabled stays pinned false — inheriting it would
newly sandbox every Bash call on a box built for unattended agents.

mutableFiles maps a source back to a repo path for the "bring changes
upstream" hint, which only works inside the flake tree. Generated sources
would print a /nix/store path to copy onto, so add upstreamPath.

rev and rev-deploy set Restart=always with RestartSec=2, which burns
systemd's default 5-starts-per-10s budget and parks the unit in `failed`
until a manual reset-failed. StartLimitIntervalSec=0 lifts the cap.

programs.nh.flake and home.mutableFilesRepoPath become mkDefault so yolo
overrides them plainly instead of with mkForce in three places.

Also clears the outstanding nixfmt and statix findings. The yolo system
derivation hash is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Miguel Palhas
2026-08-18 07:32:08 +01:00
parent 6a08ec3805
commit c79436d340
9 changed files with 107 additions and 61 deletions
+3 -6
View File
@@ -200,10 +200,6 @@
"worktree": {
"baseRef": "fresh"
},
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
},
"enabledPlugins": {
"building@subvisual": true,
"rust-analyzer-lsp@claude-plugins-official": false,
@@ -229,7 +225,6 @@
}
}
},
"tui": "fullscreen",
"skipDangerousModePermissionPrompt": true,
"theme": "dark",
"editorMode": "vim",
@@ -237,7 +232,6 @@
"autoCompactEnabled": true,
"remoteControlAtStartup": false,
"inputNeededNotifEnabled": true,
"agentPushNotifEnabled": true,
"mcpServers": {
"playwright": {
"args": [
@@ -247,5 +241,8 @@
"command": "npx",
"type": "stdio"
}
},
"sandbox": {
"enabled": false
}
}
+33 -14
View File
@@ -3,6 +3,18 @@
pkgs,
...
}:
let
claudeSettings = "home/yolo/claude-settings.json";
# ./claude-settings.json holds only what yolo overrides; everything else is
# inherited so common changes reach this host. Attrsets merge key-by-key,
# lists are replaced whole (permissions.allow is yolo's, not a union).
mergedClaudeSettings = (pkgs.formats.json { }).generate "claude-settings.json" (
lib.recursiveUpdate (lib.importJSON ../common/programs/claude/settings.json) (
lib.importJSON ./claude-settings.json
)
);
in
{
imports = [
../common/programs/default.nix
@@ -19,25 +31,32 @@
custom.hyprland.cursorSize = 32;
# Headless browser driver the agent tooling shells out to. Was a global npm
# install on the ubuntu box.
home.packages = [ pkgs.agent-browser ];
home = {
# Headless browser driver the agent tooling shells out to. Was a global npm
# install on the ubuntu box.
packages = [ pkgs.agent-browser ];
# Both default to ~/projects/nixos-config in common/programs; this clone lives
# under ~/tea. nh.flake sets NH_FLAKE, so without it `nh home switch` with no
# argument resolves to a path that does not exist.
home.mutableFilesRepoPath = lib.mkForce "/home/naps62/tea/nixos-config";
# Both default to ~/projects/nixos-config in common/programs; this clone
# lives under ~/tea. nh.flake sets NH_FLAKE, so without it `nh home switch`
# with no argument resolves to a path that does not exist.
mutableFilesRepoPath = "/home/naps62/tea/nixos-config";
# Host-local, not shared: this sets yolo_mode_default = true, which starts aoe
# sessions with permission checks skipped. Only correct on this box.
home.mutableFiles.".config/agent-of-empires/config.toml".source = ./aoe-config.toml;
mutableFiles = {
# Host-local, not shared: this sets yolo_mode_default = true, which starts
# aoe sessions with permission checks skipped. Only correct on this box.
".config/agent-of-empires/config.toml".source = ./aoe-config.toml;
# Likewise host-local: carries skipDangerousModePermissionPrompt and the rev
# hook paths, neither of which belong on a workstation.
home.mutableFiles.".claude/settings.json".source = lib.mkForce ./claude-settings.json;
# Likewise host-local: carries skipDangerousModePermissionPrompt and the
# rev hook paths, neither of which belong on a workstation.
".claude/settings.json" = {
source = lib.mkForce mergedClaudeSettings;
upstreamPath = claudeSettings;
};
};
};
programs.agentSkills.machine = "yolo";
programs.nh.flake = lib.mkForce "/home/naps62/tea/nixos-config";
programs.nh.flake = "/home/naps62/tea/nixos-config";
# Idle lock and dpms-off blank the virtual output: Sunshine then captures a
# flat frame and Moonlight goes black, with no console to unlock from.
+1 -2
View File
@@ -1,5 +1,4 @@
_:
{
_: {
# Hyprland 0.55+ is Lua-only (see home/common/programs/hyprland).
#
# Matches every output rather than naming one: the virtio-gpu connector name
+6 -2
View File
@@ -27,6 +27,10 @@ in
Unit = {
Description = "rev always-on local code review server";
After = [ "network.target" ];
# MUST stay 0: at RestartSec=2 a fast-crashing rev burns the default
# 5-starts-per-10s budget, and systemd parks the unit in `failed` until
# a manual `systemctl --user reset-failed`.
StartLimitIntervalSec = 0;
};
Service = {
Type = "simple";
@@ -51,6 +55,8 @@ in
Unit = {
Description = "rev-deploy Gitea webhook listener that deploys rev on push to main";
After = [ "network.target" ];
# Same restart-budget trap as `rev` above.
StartLimitIntervalSec = 0;
};
Service = {
Type = "simple";
@@ -119,6 +125,4 @@ in
};
};
}