| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I locked the URL (https://git.cjennings.net/dotfiles.git), the bare
repo path (/var/git/dotfiles.git), and the Phase 1 scope. Added
environment.d/envvars.conf (rofi path stripped) and
systemd/user/emacs.service to the minimal/ tree. Promoted the
DESKTOP_ENV=none VM test from optional to required. Made Phase 2's
clone explicit (sudo -u, not chown-after). Tightened Phase 3's order
so unstow and restow happen without a Hyprland reload between them.
Added a note that the new dotfiles repo can't go on GitHub until the
secrets cleanup ships, plus the post-install update flow in Step 3.3.
Replaced the "Before starting" question block with a Status table
since all five open questions are now resolved.
|
| |
|
|
|
|
|
| |
Pypr was sending stderr to /dev/null. So when its keybind clients
emitted red `hyprctl notify` banners after the daemon got stuck,
there was no trace to read. I followed the waybar / dunst /
hypridle / gammastep pattern already in the same exec-once block.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
I added a shell function that wraps `claude` and exports
CLAUDE_REMOTE_CONTROL_SESSION_NAME_PREFIX as "<short-hostname>/<cwd-basename>"
on every call. The prefix shows up in FleetView and `claude agents` so I can
tell sessions apart when several are open across projects and hosts.
I picked a function over a plain .zshrc export because $PWD has to re-evaluate
each call, not once at shell init. I picked it over an alias because the
function form is greppable and reads cleanly in `type` output.
Only affects Remote Control mode. Plain interactive `claude` is unchanged.
|
| |
|
|
| |
Covers extracting dotfiles/ into a standalone repo, adding a minimal/ stow target for headless installs, and a three-phase plan with commit boundaries. todo.org tracks the review as a sub-task.
|
| |
|
|
|
|
|
|
| |
I extended cmail-setup-finish.sh with two boot-cleanliness fixes for the systemd --user Bridge service.
The autostart cleanup removes ~/.config/autostart/Proton Mail Bridge.desktop, which double-launches Bridge and throws an "orphan instance" dialog every login.
The wait-for-dns drop-in installs an ExecStartPre loop that waits up to 30 seconds for DNS before Bridge's first API call. User-instance systemd doesn't carry network-online.target, so After=network.target doesn't imply the resolver is up. The leading '-' makes the pre-step non-fatal so an offline boot still starts the unit.
|
| |
|
|
| |
I set cursor:inactive_timeout to 2.0 so the cursor disappears after a couple of seconds without motion and reappears on the next move.
|
| |
|
|
| |
I set cursor:no_warps to true so super+j/k and other keyboard focus moves stop teleporting the cursor to the center of the newly focused window.
|
| | |
|
| |
|
|
| |
I added a [#C] task with one child per validation warning from the 18:36 VM test, each with the check it comes from and a recommendation. Most are headless-VM or QEMU-slirp false positives the test harness should skip. The lingering and Docker ones have a small real angle: logind health in the VM, and "systemctl enable docker" vs "enable --now".
|
| | |
|
| |
|
|
| |
The `validate_config()` repo check I just added used a scheme allowlist (`http(s)://`, `git://`, `ssh://`, `user@host:path`), which rejected `ARCHSETUP_REPO=/tmp/archsetup-test` in `scripts/testing/archsetup-vm.conf`. That broke the VM test: archsetup exited during validation before logging anything, and `run-test.sh` reported "ArchSetup process not found after launch". `git clone` accepts local paths and `file://` URLs fine, so the allowlist was wrong. I replaced it with a security-only check: reject a leading dash (which `git` would parse as an option) plus whitespace and control characters, allow everything else. Smoke-tested against the test config and a matrix of repo forms.
|
| |
|
|
|
|
|
|
| |
A new `validate_config()` runs whenever `--config-file` is used and rejects bad values up front instead of letting the install run partway and die: `DESKTOP_ENV` must be dwm/hyprland/none (previously only caught in the display-server step), `AUTOLOGIN`/`NO_GPU_DRIVERS` must be yes/no (previously silently ignored), `LOCALE` gets a basic shape check, and the six `*_REPO` URLs get a scheme plus no-whitespace/no-leading-dash check before they reach `git clone`.
I also pulled the username regex and reserved-names check out of `preflight_checks()` into a `validate_username()` helper, and call it from both `preflight_checks()` and `validate_config()`. That closes a gap: the old inline check only ran when the username was prompted, so a config-supplied `USERNAME=root` went through unchecked.
This is not a security boundary: `load_config` sources the config as bash, so a hostile config can already do anything. It is about catching typos with a clear message. Verified with `bash -n` and a smoke-test matrix. The next `make test` run confirms valid configs still install.
|
| |
|
|
|
|
| |
The 2026-05-11 VM test surfaced three exit-127 / "dbus-launch returned 1" errors very early in the run: `fc-cache` and the two `dconf` writes in `user_customizations()`. The function runs as step 4 of 13 (before `aur_installer`, the DE step, and most of the package installs), so the binaries the function calls are not on PATH yet.
I added `pacman_install fontconfig` and `pacman_install dconf` right before their use, mirroring the existing `pacman_install desktop-file-utils` pattern in the same function. Both are idempotent. Verified by `bash -n`. The next `make test` run confirms the behavior in the VM.
|
| |
|
|
|
|
| |
I added a TODO for the 7 errors logged during the run. A few look real: fc-cache and dconf hit exit 127, and gamemode failed for the user. A couple look like VM/nf_tables artifacts I want to confirm on bare metal.
I moved the rlwrap-not-installed investigation to Resolved (DONE). rlwrap installs cleanly in a fresh VM, so the ratio glitch does not reproduce. The test-infra fix from the previous commit is also logged as DONE in Resolved.
|
| |
|
|
|
|
| |
validate_hyprland_plugins and validate_hyprpm_hook checked for the hyprland-plugins-setup script and the hyprpm pacman hook, both removed in 4a3056a (Hyprland 0.54 brings the layouts into core). I deleted the two functions and their calls in validate_window_manager.
I also disabled errexit in run-test.sh from the validation phase onward, so one failed check is counted in VALIDATION_FAILED instead of aborting the run before the report or VM cleanup. About 16 validations across the file do a bare `return 1` after `validation_fail`; any of them firing under the previous behavior would have killed the harness mid-run.
|
| | |
|
| |
|
|
| |
Moved 13 completed tasks into the Resolved section. Recorded the open-source-release source audit and the dotfile-separation plan as dated subheaders under their tasks.
|
| |
|
|
| |
Initial README. Personal values (emails, URLs, repo names, the temporary root password) are placeholders for the eventual public release. LICENSE is the canonical GPL-3.0 license text.
|
| |
|
|
|
|
| |
Long-running tmux+vterm sessions (Claude Code's TUI in particular) run past 50k lines often enough that the C-; x C tmux-history-copy command in Emacs can't reach the start. Bump history-limit so `tmux capture-pane' has more room; the cost is roughly 7.5 MB per pane, so a six-pane session adds well under 100 MB total.
Existing panes keep their current buffer; the new limit applies only to panes created after the reload.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Bridge first-run is interactive, so I put the cmail wiring in a post-install
helper rather than running it inside archsetup. scripts/cmail-setup-finish.sh
handles the post-first-run steps idempotently: it decrypts the encrypted
cmailpass, copies Bridge's self-signed cert to ~/.config/protonbridge.pem,
symlinks the cmail-action triage helper into ~/.local/bin, and enables the
user-level protonmail-bridge service.
I added loginctl enable-linger in essential_services so the user service
survives logout — without it, triaging cmail from a remote agent or SSH
session has nothing to talk to. outro prints a four-step runbook for the
manual steps after reboot.
|
| |
|
|
|
|
| |
I removed the `ai-assistants` tmux launcher and the `.claude/settings.local.json` permissions stub from the stowed common dotfiles. The two `aliases.sh` files (bash and zsh) each lost a matching 5-line comment block about the Claude `ai` launcher. None of these belong in a shared dotfile tree.
Two small adjacent updates landed in the same commit. The gitconfig `includeIf` path moved from `~/code/deepsat/` to `~/projects/work/deepsat/code/` to match the on-disk layout. Qalculate auto-saved its config version bump from 5.9.0 to 5.10.0.
|
| | |
|
| |
|
|
|
|
| |
The previous block ran three operations under one error_warn: `cd "$dotfiles_dir" && git config --global --add safe.directory ... && git restore .`. If any one of them failed, the operator saw a single "restoring dotfile versions" warning with no clue which step broke. The cd was unnecessary because git's `-C` flag does the same thing without changing the calling shell's working directory.
I split the block into two guarded steps. The `safe.directory` config runs first with its own error_warn. If that step succeeds, the `git restore` runs next with its own error_warn. If `safe.directory` fails, the dotfile restore is skipped entirely. The original cause gets logged once instead of cascading into a second error from git's dubious-ownership check. I also dropped the `cd` and used `git -C "$dotfiles_dir"` instead.
|
| |
|
|
|
|
| |
The `source = $HOME/.config/hypr/conf.d/*.conf` line was at the top of `hyprland.conf` (line 9), before the `general`, `input`, `monitor`, and other blocks. Hyprland reads top to bottom, so anything later in the main file silently overrode whatever `conf.d/local.conf` set. `local.conf` exists so one machine can override the shared defaults, for instance a HiDPI laptop bumping its monitor scale or shrinking gaps. None of that worked.
I moved the source line to the end of the file behind a labeled section comment. Now per-machine overrides take effect. To verify, I dropped a `general { gaps_in = 99 }` into a temporary file in `conf.d/` and reloaded. `hyprctl getoption general:gaps_in` came back as 99 instead of the main file's 25. I removed the test file and the value went back to 25.
|
| |
|
|
|
|
| |
The `input` block had `natural_scroll = true` only inside its `touchpad` sub-block. The BT mouse fell back to Hyprland's default and scrolled the opposite way from the touchpad. Switching between input devices flipped scroll direction.
I added `natural_scroll = true` at the top level of the `input` block. The touchpad's own setting still applies because Hyprland scopes touchpad config separately. Touchpad behavior is unchanged.
|
| |
|
|
|
|
| |
archinstall writes the /efi line to /etc/fstab with `defaults` (or similar) and no fmask/dmask, so files inside end up 0755. Kernel images, initramfs, and bootloader config are world-readable on a freshly installed system. On a single-user machine that's mild, but there's no good reason to leave it that way.
I added a guarded sed to boot_ux() that appends `fmask=0177,dmask=0077` to the /efi vfat line. Files end up 0600 and dirs 0700, root-only. The block is idempotent. Both guards check that the /efi line exists and that fmask= isn't already there before touching anything. I patched this machine's fstab the same way, so the new options take effect on next boot.
|
| |
|
|
|
|
| |
Pyprland 3.4 started applying a `group deny` windowrule to every scratchpad. In Hyprland that flag routes the border through `col.nogroup_border` and `col.nogroup_border_active` instead of the regular `col.*_border` colors. Hyprland's defaults for those two are pink and bright magenta, so every scratchpad came up with a glaring magenta frame after the 3.4 upgrade.
I set `col.nogroup_border_active` to dupre blue (#67809c) and `col.nogroup_border` to the same dark grey the inactive border already uses. Focused scratchpads read as a deliberate accent, unfocused ones blend in. The two new lines sit next to the existing `col.*_border` entries with a comment naming the cause, so the next person reading this config doesn't have to re-derive it.
|
| |
|
|
|
|
| |
I moved settings.json, .mcp.json, and commands/refactor.md to the rulesets repo so they travel across machines instead of being archsetup-specific. The local ~/.claude/ symlinks now point at rulesets.
I also added the three paths to .gitignore so a stray re-add of any of them won't slip through. settings.local.json stays here because it's per-machine by convention.
|
| |
|
|
| |
I dropped frontend-design, ralph-loop, security-guidance, and context7 from enabledPlugins. Context7 saw three tool calls across months of sessions. I never used the other three at all. I also switched editorMode back to emacs because the readline default fits my flow better than vim mode.
|
| |
|
|
| |
I moved humanizer to the rulesets repo where the rest of the skills live. The local ~/.claude/skills/humanizer symlink now points at the new location. That leaves no more skills under archsetup, so the empty .claude/skills directory is gone too.
|
| |
|
|
| |
I changed the default browser to Firefox. I also added ~/.cask/bin to PATH.
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
New dmail IMAP group with the standard 5-channel layout (inbox, sent, drafts, trash, starred), mirroring the gmail block. Matching SMTP account uses passwordeval against an encrypted password file at .config/.dmailpass.gpg.
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
If no YYYY-MM-DD matches, the script now looks for a 10-digit epoch between underscores in the filename and converts it via date -d. The existing 24-hour mtime guard still protects the active session log from being deleted while it's still being written to.
|
| |
|
|
| |
now ignoring all __pycache__ directories
|
| |
|
|
|
|
| |
Remove git-commit and gh-pr-create confirmation hooks, remove
code-review plugin, reorder keys alphabetically, and enable vim
editor mode.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
When focus is inside a special workspace (e.g. special:stash),
layoutmsg cyclenext/cycleprev only operates within that workspace,
trapping $mod+J inside the scratchpad overlay.
Detect workspace name starting with "special:" on focus navigation
(not move), toggle the overlay off first, re-read active window
state, then fall through to the normal layout/floating branches.
Add unit tests with a fake hyprctl harness in
tests/layout-navigate/. ```
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Merges live ~/.claude/settings.json content (hooks: PreCompact +
PreToolUse/Bash with git-commit-confirm, gh-pr-create-confirm,
destructive-bash-confirm; enabledPlugins) into the archsetup source
that velox was already symlinking.
Previous state: velox symlinked archsetup source (attribution only,
missing hooks/plugins). Ratio had a standalone file (hooks/plugins
but no attribution). Both machines asymmetric and incomplete.
Now: single source of truth in archsetup/dotfiles/common/.claude/
settings.json. Ratio needs to replace standalone file with symlink
(manual step per-machine).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds the empty-string attribution block that disables Claude Code's
auto-added attribution lines (Co-Authored-By, 'Generated with Claude
Code', etc.) at the tool layer, matching the existing 'no Claude
attribution' rule in protocols.org.
Two complementary enforcement layers now:
- prompt-level rule (protocols.org)
- tool-level setting (this commit)
Same intent already lives in rulesets/languages/elisp/claude/settings.json
for elisp project bundles; this brings it to the global Claude Code
config that ships via archsetup.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Both the aix script and hey shell function are superseded by the
unified 'ai' launcher in claude-templates (bin/ai, installed via
make install). Single command, three modes, smart in-tmux behavior
so all sessions survive Hyprland crashes.
Per-machine setup adds a step:
cd ~/projects/claude-templates && make install
The orphaned ~/.local/bin/aix symlink should be removed manually on
each machine after pulling this change (rm ~/.local/bin/aix). Stow
re-stow would also clean it up.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The 'hey' alias launched claude with 'Read docs/protocols.org' — broken
after the docs/ → .ai/ restructure. While updating the path, add
matching behavior to aix:
- Bail early if the current dir isn't a .ai/ template project
- Fetch upstream only when FETCH_HEAD is stale (>10 min old) — avoids
re-fetching on back-to-back invocations in the same project
- Auto-pull when clean, behind, not ahead
- Print a one-line git-status summary otherwise (↑N ↓N dirty)
- Launch claude with the updated .ai/protocols.org path
Function identical across .bashrc.d and .zshrc.d (bash/zsh compatible).
Tested: non-template dir bails cleanly with exit 1; template project
shows status and launches claude; repeated invocations reuse
FETCH_HEAD cache silently.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds multi-machine sync awareness to the session launcher.
Before fzf:
- Fetches all candidate repos in parallel (capped at 6 concurrent)
- Annotates each entry with git status: (↑N ↓N dirty), (no upstream)
- Clean repos show no annotation
When launching a window:
- If working tree is clean, has upstream, is behind (not ahead): pull
- Otherwise: open window as-is, user handles any sync manually
Design choices:
- Fetches are synchronous — accurate status at the cost of a brief wait
on session start. Parallel execution keeps it fast (~1-2s for 22 repos).
- Pull is --ff-only — never merges, never creates merge commits in aix
- Diverged repos (ahead AND behind) trigger no auto-action; user decides
- No stash/pop dance — unreliable in multi-project batches; prefer
explicit awareness via annotation
Primary use case: moving between laptop and desktop. Wrap-it-up's
always-push ensures remote is current at session end; this ensures
local is current at next session start.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two changes:
- AI_INSTRUCTIONS now points at .ai/protocols.org (was docs/) — aligns
with the template docs/ → .ai/ restructure
- build_candidates filters directories to those with .ai/protocols.org
present. Previously listed every dir under ~/code/ and ~/projects/
including third-party clones and non-template projects, which would
fail silently when Claude tried to read a missing protocols file.
New projects that haven't been initialized (no .ai/ yet) will not
appear in the fzf list. Bootstrap those with a direct claude
invocation; the first-session workflow takes over once .ai/ exists.
|
| |
|
|
|
|
|
| |
Missed in the main migration commit (sed pattern didn't match the
layout table or the standalone 'docs/' reference in the note line).
Layout now lists .ai/ correctly; gitignore note refers to .ai/
instead of docs/.
|