From c9c6a9507767d0b9aafb045450d7380b6c4ca35c Mon Sep 17 00:00:00 2001
From: Barrett Ruth
Date: Wed, 11 Feb 2026 12:01:49 -0500
Subject: [PATCH] migrate claud config
---
config/claude/CLAUDE.md | 32 +++++++++++
config/claude/rules/git.md | 85 ++++++++++++++++++++++++++++
config/claude/skills/commit/SKILL.md | 43 ++++++++++++++
config/claude/skills/pr/SKILL.md | 44 ++++++++++++++
config/nvim/lua/plugins/git.lua | 1 +
home/modules/packages.nix | 12 ++++
6 files changed, 217 insertions(+)
create mode 100644 config/claude/CLAUDE.md
create mode 100644 config/claude/rules/git.md
create mode 100644 config/claude/skills/commit/SKILL.md
create mode 100644 config/claude/skills/pr/SKILL.md
diff --git a/config/claude/CLAUDE.md b/config/claude/CLAUDE.md
new file mode 100644
index 0000000..cae28fa
--- /dev/null
+++ b/config/claude/CLAUDE.md
@@ -0,0 +1,32 @@
+# Global Claude Code User Preferences
+
+Never, under any circumstances, generate code containing new, non-preexisting comments.
+
+Never, under any circumstances, respond with excerpts of code with no
+explanation unless explicitly specified.
+
+Never, under any circumstances, create commits, stage files, or create pull
+requests unless explicitly specified.
+
+If given express permission to use git, NEVER sign yourself as a contributor OR mention yourself in the PR.
+
+If given express permission to use git, NEVER push to a main/master branch.
+
+If given express permission to use git, NEVER commit ai-related files (e.g. CLAUDE.md).
+
+If given express permission to use git, ALWAYS use this commit message format:
+
+ type(scope): imperative summary
+
+- Valid types: `feat` `fix` `docs` `refactor` `perf` `test` `ci` `build` `revert`
+- Scope is optional, lowercase. Subject: lowercase after colon, no trailing period, max 72 chars.
+- Body required for non-trivial commits, using `Problem:` / `Solution:` format.
+- One logical change per commit. Refactors, formatting, and features must be separate commits.
+
+If given express permission to use git, ALWAYS check for a PR template at
+`.github/pull_request_template.md` and follow it. If none exists, use
+Problem/Solution format as described in `~/.config/claude/rules/git.md`.
+
+Never, under any circumstances, assume or fabricate APIs for
+unknown/lesser-known services and APIs, such as NeoVim, NixOS, or other obscure
+packages-always do your research first.
diff --git a/config/claude/rules/git.md b/config/claude/rules/git.md
new file mode 100644
index 0000000..bebf047
--- /dev/null
+++ b/config/claude/rules/git.md
@@ -0,0 +1,85 @@
+# Git Workflow Rules
+
+## Commit Message Format
+
+```
+type(scope): imperative summary
+
+Problem: describe the issue or motivation
+
+Solution: describe what this commit does
+```
+
+### Header
+
+- **type** (required): `feat` `fix` `docs` `refactor` `perf` `test` `ci` `build` `revert`
+- **scope** (optional): lowercase module/area name, e.g. `feat(parser):`
+- **summary**: imperative mood, lowercase after colon, no trailing period, max 72 chars
+
+### Body
+
+Required for any non-trivial change. Use `Problem:` / `Solution:` sections.
+Wrap at 72 characters. Separate from header with a blank line.
+
+### Examples
+
+Good:
+
+```
+fix(lsp): correct off-by-one in diagnostic range
+
+Problem: diagnostics highlighted one character past the actual error,
+causing confusion when multiple diagnostics appeared on adjacent tokens.
+
+Solution: subtract 1 from the end column returned by the language server
+before converting to 0-indexed nvim columns.
+```
+
+```
+refactor: extract repeated buffer lookup into helper
+```
+
+Bad:
+
+```
+Fixed stuff # not imperative, vague
+feat: Add Feature. # uppercase after colon, trailing period
+fix(lsp): correct off-by-one in diagnostic range and also refactor the
+entire highlight module and add new tests # multiple concerns
+```
+
+## Branch Naming
+
+```
+type/short-description
+```
+
+Examples: `fix/diagnostic-range`, `feat/code-actions`, `refactor/highlight-module`
+
+## PR Body Format
+
+If the repo has `.github/pull_request_template.md`, follow that template exactly.
+
+If no template exists, fall back to:
+
+```
+## Problem
+
+
+
+## Solution
+
+
+```
+
+Either way, write in plain prose. No bullet-point walls, no AI-style markdown
+headings beyond what the template calls for. Keep it concise and human.
+
+## Decomposition Rules
+
+- One logical change per commit.
+- Refactors go in their own commit before the feature that depends on them.
+- Formatting/style changes are never mixed with behavioral changes.
+- Test-only commits are fine when adding coverage for existing code.
+- If a PR has more than ~3 commits, consider whether it should be split into
+ separate PRs.
diff --git a/config/claude/skills/commit/SKILL.md b/config/claude/skills/commit/SKILL.md
new file mode 100644
index 0000000..fa2a5ed
--- /dev/null
+++ b/config/claude/skills/commit/SKILL.md
@@ -0,0 +1,43 @@
+# /commit
+
+Create a conventional commit from staged or unstaged changes.
+
+## Instructions
+
+1. Run exactly this one Bash command:
+ ```
+ git status --short && echo "---DIFF---" && git diff --cached && echo "---LOG---" && git log --oneline -5
+ ```
+
+2. If the diff section is empty (nothing staged), ask the user which files to
+ stage from the status list. Then run exactly one Bash command:
+ ```
+ git add && git diff --cached
+ ```
+ Do NOT re-run status or log — you already have them.
+
+3. Draft the commit message. Rules:
+ - Header: `type(scope): imperative summary` — max 72 chars, lowercase after
+ colon, no trailing period.
+ - Valid types: `feat` `fix` `docs` `refactor` `perf` `test` `ci` `build` `revert`
+ - Scope is optional, lowercase.
+ - Non-trivial changes require a body with `Problem:` / `Solution:` sections,
+ wrapped at 72 chars, separated from header by a blank line.
+ - Trivial one-liners: header alone is fine.
+ - Match the style of the recent commits from step 1.
+
+4. Present the full message and ask for approval.
+
+5. After approval, run exactly one Bash command:
+ ```
+ git commit -m "$(cat <<'EOF'
+
+ EOF
+ )"
+ ```
+
+Total: 2 Bash calls (gather + commit), or 3 if staging was needed. Do not run
+any other commands. Do not read files, explore code, or run additional git
+commands beyond what is listed above.
+
+Never amend. Never sign as co-author. Never push.
diff --git a/config/claude/skills/pr/SKILL.md b/config/claude/skills/pr/SKILL.md
new file mode 100644
index 0000000..44d09bd
--- /dev/null
+++ b/config/claude/skills/pr/SKILL.md
@@ -0,0 +1,44 @@
+# /pr
+
+Create a pull request from the current branch.
+
+## Instructions
+
+1. Run exactly this one Bash command:
+ ```
+ echo "---BRANCH---" && git branch --show-current && echo "---LOG---" && git log --oneline main..HEAD && echo "---STAT---" && git diff main...HEAD --stat && echo "---TEMPLATE---" && cat .github/pull_request_template.md 2>/dev/null || true
+ ```
+ If the branch is `main` or `master`, tell the user and stop.
+
+2. Draft the PR using the commit log and diffstat (do NOT run `git diff` for the
+ full diff — you already have conversation context from the work you did):
+ - **Title**: `type(scope): imperative summary`, max 72 chars. For
+ single-commit PRs, reuse the commit header. For multi-commit, summarize.
+ - **Body**: if a PR template was found in step 1, fill it in. Otherwise:
+ ```
+ ## Problem
+
+
+
+ ## Solution
+
+
+ ```
+ - Write in plain prose. No bullet walls, no AI markdown soup.
+
+3. Present the title and body. Ask for approval.
+
+4. After approval, run exactly one Bash command (push + create chained):
+ ```
+ git push -u origin && gh pr create --title "" --body "$(cat <<'EOF'
+
+ EOF
+ )"
+ ```
+ Print the PR URL from the output.
+
+Total: 2 Bash calls (gather + push/create). Do not run any other commands. Do
+not read files, explore code, or run additional git commands beyond what is
+listed above.
+
+Never force-push, even with lease. Never target main/master as the head branch.
diff --git a/config/nvim/lua/plugins/git.lua b/config/nvim/lua/plugins/git.lua
index ad551c6..33b4f79 100644
--- a/config/nvim/lua/plugins/git.lua
+++ b/config/nvim/lua/plugins/git.lua
@@ -7,6 +7,7 @@ return {
cmd = { 'Git', 'G', 'Gread', 'Gwrite', 'Gdiffsplit', 'Gvdiffsplit' },
},
{
+ dir = '~/dev/diffs.nvim',
'barrettruth/diffs.nvim',
init = function()
vim.g.diffs = {
diff --git a/home/modules/packages.nix b/home/modules/packages.nix
index 40d0774..0c6248e 100644
--- a/home/modules/packages.nix
+++ b/home/modules/packages.nix
@@ -51,6 +51,18 @@ in
};
};
+ xdg.configFile."claude/CLAUDE.md" = lib.mkIf enableClaude {
+ source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.config/nix/config/claude/CLAUDE.md";
+ };
+
+ xdg.configFile."claude/rules" = lib.mkIf enableClaude {
+ source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.config/nix/config/claude/rules";
+ };
+
+ xdg.configFile."claude/skills" = lib.mkIf enableClaude {
+ source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.config/nix/config/claude/skills";
+ };
+
home.activation.linkZenProfile = lib.mkIf enableZen (
lib.hm.dag.entryAfter [ "writeBoundary" ] ''
zen_config="$HOME/.zen"