aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/cmail-setup-finish.sh44
-rwxr-xr-xscripts/post-rebuild-check11
-rw-r--r--tests/post-rebuild-check/test_post_rebuild_check.py23
-rw-r--r--todo.org6
4 files changed, 58 insertions, 26 deletions
diff --git a/scripts/cmail-setup-finish.sh b/scripts/cmail-setup-finish.sh
index 949023f..bd72499 100755
--- a/scripts/cmail-setup-finish.sh
+++ b/scripts/cmail-setup-finish.sh
@@ -1,28 +1,29 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
-# cmail-setup-finish.sh — finish Proton Mail Bridge + cmail-action setup after
-# Bridge first-run. Idempotent; safe to re-run after a Bridge cert rotation or
-# a claude-templates re-clone.
+# cmail-setup-finish.sh — finish Proton Mail Bridge setup after Bridge
+# first-run. Idempotent; safe to re-run after a Bridge cert rotation.
#
# Pre-reqs (the script aborts if any are missing):
# - protonmail-bridge installed (archsetup handles it)
# - You have run 'protonmail-bridge --cli', logged in, and quit at least once
# (the script looks for state at ~/.config/protonmail/bridge-v3/)
-# - claude-templates cloned at ~/projects/claude-templates
+# - cmail-action on PATH (rulesets' `make install` links it; session start
+# runs that, so it arrives on its own)
# - dotfiles stowed (~/.config/.cmailpass.gpg present)
#
# What it does:
# 1. Decrypts ~/.config/.cmailpass.gpg → ~/.config/.cmailpass (mode 0600)
# 2. Copies Bridge's self-signed cert → ~/.config/protonbridge.pem
-# 3. Symlinks ~/projects/claude-templates/.ai/scripts/cmail-action.py
-# → ~/.local/bin/cmail-action
-# 4. Removes the leftover ~/.config/autostart/Proton Mail Bridge.desktop
+# 3. Removes the leftover ~/.config/autostart/Proton Mail Bridge.desktop
# stub (it double-launches Bridge alongside the systemd user service
# and throws an "orphan instance" dialog every login)
-# 5. Installs a wait-for-dns drop-in so Bridge doesn't spam
+# 4. Installs a wait-for-dns drop-in so Bridge doesn't spam
# name-resolution errors during the early-boot DNS race
-# 6. Enables + starts the protonmail-bridge user service
-# 7. Verifies Bridge is listening on 127.0.0.1:1143 / :1025
+# 5. Enables + starts the protonmail-bridge user service
+# 6. Verifies Bridge is listening on 127.0.0.1:1143 / :1025
+#
+# It no longer installs cmail-action. That moved to rulesets
+# (claude-templates/bin/), whose `make install` owns the symlink.
set -euo pipefail
@@ -47,9 +48,12 @@ bridge_state="$HOME/.config/protonmail/bridge-v3"
[ -d "$bridge_state" ] \
|| err "Bridge has no state at $bridge_state — run 'protonmail-bridge --cli' and log in first"
-cmail_action_src="$HOME/projects/claude-templates/.ai/scripts/cmail-action.py"
-[ -f "$cmail_action_src" ] \
- || err "cmail-action.py not found at $cmail_action_src — clone claude-templates first"
+# cmail-action is no longer this script's to install. It lives in rulesets at
+# claude-templates/bin/, and rulesets' `make install` links everything there
+# into ~/.local/bin — which every session start runs, so the symlink reaches
+# each machine on its own. Check that it arrived rather than placing it.
+command -v cmail-action >/dev/null 2>&1 \
+ || err "cmail-action not on PATH — run 'make -C ~/code/rulesets install'"
cmailpass_enc="$HOME/.config/.cmailpass.gpg"
[ -f "$cmailpass_enc" ] \
@@ -69,13 +73,7 @@ cert_dst="$HOME/.config/protonbridge.pem"
cp "$cert_src" "$cert_dst"
ok "copied $cert_src → $cert_dst"
-# 4. Symlink cmail-action
-info "symlinking cmail-action"
-mkdir -p "$HOME/.local/bin"
-ln -sf "$cmail_action_src" "$HOME/.local/bin/cmail-action"
-ok "linked $HOME/.local/bin/cmail-action → $cmail_action_src"
-
-# 5. Remove leftover XDG autostart stub
+# 4. Remove leftover XDG autostart stub
# The systemd --user service is the canonical launcher. The autostart .desktop
# starts a second Bridge instance that can't get the lock and pops up an
# "orphan instance" dialog every login.
@@ -88,7 +86,7 @@ else
ok "no autostart stub present"
fi
-# 6. Install wait-for-dns drop-in
+# 5. Install wait-for-dns drop-in
# User-instance systemd doesn't carry network-online.target / nss-lookup.target,
# so the packaged unit's After=network.target doesn't imply DNS readiness.
# Bridge starts before the resolver is up and its first API calls all fail
@@ -107,7 +105,7 @@ ok "wrote $dropin_file"
systemctl --user daemon-reload
ok "reloaded systemd user units"
-# 7. Enable + start systemd user service
+# 6. Enable + start systemd user service
info "enabling protonmail-bridge user service"
was_active=0
systemctl --user is-active --quiet protonmail-bridge.service && was_active=1
@@ -119,7 +117,7 @@ else
ok "service active"
fi
-# 8. Verify
+# 7. Verify
info "verifying Bridge is listening"
listening="$(ss -ltn 2>/dev/null || true)"
missing=""
diff --git a/scripts/post-rebuild-check b/scripts/post-rebuild-check
index ee77a19..aa7ef83 100755
--- a/scripts/post-rebuild-check
+++ b/scripts/post-rebuild-check
@@ -428,6 +428,16 @@ printf '%s\n' "$projects" > "$WORK/projects" 2>/dev/null || {
# steady state rather than reinstall drift, and flagging it would put nine
# standing findings in front of every real one.
#
+# .claude/ is absent for the same reason and proven the same way. The
+# bootstrap and the gitignore sweep write it into the ignore set of every
+# gitignore-mode project whether or not one ever exists there, so the entry is
+# aspirational rather than a promise -- pearl, rsyncshot and yt-sync each name
+# it and none of the three has ever had one, on velox or on ratio. Dropping it
+# loses no real signal either: a project that genuinely carries a .claude/
+# (rules and hooks from a language bundle) has it re-synced by
+# sync-language-bundle.sh at every session start, so a true absence heals
+# itself before this check would run.
+#
# The list is fed to the inner loop straight from a heredoc rather than
# staged through a file. It is a constant, so a file bought nothing and cost
# a fifth unguarded write: had it failed (a full tmpfs, say) the inner loop
@@ -458,7 +468,6 @@ while IFS= read -r proj; do
esac
done <<'EOF'
.ai \.ai
-.claude \.claude
todo.org todo\.org
inbox inbox
EOF
diff --git a/tests/post-rebuild-check/test_post_rebuild_check.py b/tests/post-rebuild-check/test_post_rebuild_check.py
index a034f87..bc887c6 100644
--- a/tests/post-rebuild-check/test_post_rebuild_check.py
+++ b/tests/post-rebuild-check/test_post_rebuild_check.py
@@ -765,12 +765,31 @@ class ProjectTooling(unittest.TestCase):
def test_ignored_but_absent_tooling_flags(self):
with tempfile.TemporaryDirectory() as root:
- self.project(root, [".ai/", ".claude/", "todo.org"])
+ self.project(root, [".ai/", "todo.org"])
r = run_check(project_roots=root)
self.assertEqual(r.returncode, 1)
- for missing in (".ai", ".claude", "todo.org"):
+ for missing in (".ai", "todo.org"):
self.assertIn(missing, r.stdout)
+ def test_claude_dir_absence_never_flags(self):
+ # Same shape as CLAUDE.md below, and proven the same way. The bootstrap
+ # and the gitignore sweep write `.claude/` into the ignore set of every
+ # gitignore-mode project whether or not one ever exists there, so the
+ # entry is aspirational rather than a promise. Three projects tripped
+ # this on velox, and ratio is missing the identical directory in the
+ # identical three, which is what proves it is the steady state and not
+ # reinstall drift.
+ #
+ # Nor does dropping it lose a real signal. A project that genuinely
+ # carries one (rules and hooks from a language bundle) has it re-synced
+ # by sync-language-bundle.sh at every session start, so a true absence
+ # heals itself before this check would ever run.
+ with tempfile.TemporaryDirectory() as root:
+ self.project(root, [".ai/", ".claude/"], present=(".ai/",))
+ r = run_check(project_roots=root)
+ self.assertEqual(r.returncode, 0, r.stdout)
+ self.assertNotIn(".claude", r.stdout)
+
def test_ignored_and_present_tooling_passes(self):
with tempfile.TemporaryDirectory() as root:
self.project(root, [".ai/", "CLAUDE.md"],
diff --git a/todo.org b/todo.org
index 28872f8..d9a8eae 100644
--- a/todo.org
+++ b/todo.org
@@ -3913,6 +3913,12 @@ From the roam inbox (Craig, claimed 2026-07-23): velox needs bringing up to date
Resolved 2026-07-23 by a full sweep over tailscale. The touchpad module was already gone — velox's running waybar (started 01:05, after the reboot) and its tracked config both carry zero =custom/touchpad= entries; what Craig saw was the pre-restow waybar process from before the reboot, and the reboot cleared it. Sweep results: both machines at dotfiles f9b6404 (all three hyprland lock/exit fixes live on velox, config errors clean, =allow_session_lock_restore= reads true); stow restow clean, only the expected skip-worktree files; rulesets pulled to 50fc7ca and =make install= run (agent-text verified working by invoking it — an earlier "MISSING" reading was a PATH artifact of the non-interactive ssh shell, not a real gap); desktop-settings tick timer active; mpvpaper, power-profiles-daemon, gtk4-layer-shell, webkit2gtk all present.
Genuine remaining differences, all per-machine installs rather than sync failures: =cmail-action=, =gcalcli=, and =playwright= aren't installed on velox, and =obsbot-wb-guard.service= isn't enabled there (the OBSBOT lives on ratio). None block anything; file separately if velox should send mail or drive browser tests.
+*** 2026-08-20 Thu @ 09:53:04 -0700 One of those three closed itself; two still stand
+=cmail-action= is on both daily drivers now, and nothing did it deliberately. It moved into rulesets at =claude-templates/bin/=, and rulesets' =make install= links that whole directory into =~/.local/bin= at every session start — so velox picked it up on its own. Verified here: the symlink was written 05:44 this morning by this session's own startup, and the tool runs.
+
+=gcalcli= and =playwright= are still absent on velox, which stays correct until I say velox should send calendar invites or drive browser tests. =obsbot-wb-guard= is still right to be off here; the camera is on ratio.
+
+Leaving the paragraph above as written rather than striking it (rulesets suggested striking). It is the resolution note of a task closed 2026-07-23 and it was accurate that day. Editing a closed record to match today makes it a worse record, and the useful correction is this dated entry, not a redaction.
** DONE [#C] Weather tooltip sunrise and sunset :feature:waybar:weather:quick:solo:
CLOSED: [2026-07-23 Thu]
Shipped 2026-07-23 as dotfiles =de62e9d=. The two rows sit directly below Humidity in the current-conditions block, rendered in the footer's 12-hour format (=%-I:%M %p=) so the tooltip reads one way throughout.