feat(claude): improve ai workflow
This commit is contained in:
parent
e84a22dbcb
commit
902f0f3ad6
11 changed files with 196 additions and 33 deletions
|
|
@ -14,6 +14,10 @@ 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, NEVER commit ai-related files (e.g. CLAUDE.md).
|
||||||
|
|
||||||
|
If given express permission to use git, ALWAYS work on a feature branch. If on
|
||||||
|
`main` or `master`, create and switch to a branch before making changes. Branch
|
||||||
|
naming: `type/short-description` (e.g. `fix/diagnostic-range`).
|
||||||
|
|
||||||
If given express permission to use git, ALWAYS use this commit message format:
|
If given express permission to use git, ALWAYS use this commit message format:
|
||||||
|
|
||||||
type(scope): imperative summary
|
type(scope): imperative summary
|
||||||
|
|
@ -21,7 +25,10 @@ If given express permission to use git, ALWAYS use this commit message format:
|
||||||
- Valid types: `feat` `fix` `docs` `refactor` `perf` `test` `ci` `build` `revert`
|
- 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.
|
- Scope is optional, lowercase. Subject: lowercase after colon, no trailing period, max 72 chars.
|
||||||
- Body required for non-trivial commits, using `Problem:` / `Solution:` format.
|
- Body required for non-trivial commits, using `Problem:` / `Solution:` format.
|
||||||
|
Keep each section to 2-3 sentences.
|
||||||
- One logical change per commit. Refactors, formatting, and features must be separate commits.
|
- One logical change per commit. Refactors, formatting, and features must be separate commits.
|
||||||
|
- Use backticks around code identifiers, function names, and file paths in
|
||||||
|
commit messages and PR descriptions (e.g. `setup()`, `lua/oil/view.lua`).
|
||||||
|
|
||||||
If given express permission to use git, ALWAYS check for a PR template at
|
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
|
`.github/pull_request_template.md` and follow it. If none exists, use
|
||||||
|
|
|
||||||
25
config/claude/hooks/guard.sh
Executable file
25
config/claude/hooks/guard.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
INPUT=$(cat)
|
||||||
|
CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty')
|
||||||
|
|
||||||
|
if printf '%s' "$CMD" | grep -qE '\bgh\b.*\s(-R|--repo)\b'; then
|
||||||
|
echo "Blocked: do not target other repos with -R/--repo. Run gh commands against the current repo only." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s' "$CMD" | grep -qE '\bgh\s+issue\s+create\b'; then
|
||||||
|
echo "Blocked: gh issue create must be run manually or explicitly approved." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s' "$CMD" | grep -qE '\bgit\s+push\b'; then
|
||||||
|
BRANCH=$(git branch --show-current 2>/dev/null || true)
|
||||||
|
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
|
||||||
|
echo "Blocked: never push directly to $BRANCH. Use a feature branch." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
@ -19,36 +19,43 @@ Solution: describe what this commit does
|
||||||
### Body
|
### Body
|
||||||
|
|
||||||
Required for any non-trivial change. Use `Problem:` / `Solution:` sections.
|
Required for any non-trivial change. Use `Problem:` / `Solution:` sections.
|
||||||
Wrap at 72 characters. Separate from header with a blank line.
|
2-3 sentences per section, max. Wrap at 72 characters. Separate from header
|
||||||
|
with a blank line.
|
||||||
|
|
||||||
|
Use backticks around code identifiers, function names, and file paths
|
||||||
|
(e.g. `setup()`, `lua/oil/view.lua`, `FIELD_NAME`).
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
Good:
|
Good:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix(lsp): correct off-by-one in diagnostic range
|
fix(lsp): correct off-by-one in `diagnostic_range`
|
||||||
|
|
||||||
Problem: diagnostics highlighted one character past the actual error,
|
Problem: diagnostics highlighted one character past the actual error,
|
||||||
causing confusion when multiple diagnostics appeared on adjacent tokens.
|
causing confusion on adjacent tokens.
|
||||||
|
|
||||||
Solution: subtract 1 from the end column returned by the language server
|
Solution: subtract 1 from the end column returned by the language
|
||||||
before converting to 0-indexed nvim columns.
|
server before converting to 0-indexed nvim columns.
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
refactor: extract repeated buffer lookup into helper
|
refactor: extract repeated buffer lookup into `get_buf_entry`
|
||||||
```
|
```
|
||||||
|
|
||||||
Bad:
|
Bad:
|
||||||
|
|
||||||
```
|
```
|
||||||
Fixed stuff # not imperative, vague
|
Fixed stuff
|
||||||
feat: Add Feature. # uppercase after colon, trailing period
|
feat: Add Feature.
|
||||||
fix(lsp): correct off-by-one in diagnostic range and also refactor the
|
fix(lsp): correct off-by-one in diagnostic range and also refactor the
|
||||||
entire highlight module and add new tests # multiple concerns
|
entire highlight module and add new tests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Branch Naming
|
## Branch Rules
|
||||||
|
|
||||||
|
Always work on a feature branch. Never commit or push directly to `main` or
|
||||||
|
`master`. If on the default branch, create and switch to a topic branch first.
|
||||||
|
|
||||||
```
|
```
|
||||||
type/short-description
|
type/short-description
|
||||||
|
|
@ -65,15 +72,15 @@ If no template exists, fall back to:
|
||||||
```
|
```
|
||||||
## Problem
|
## Problem
|
||||||
|
|
||||||
<why this change is needed>
|
<1-2 sentences>
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
|
|
||||||
<what the change does>
|
<1-2 sentences>
|
||||||
```
|
```
|
||||||
|
|
||||||
Either way, write in plain prose. No bullet-point walls, no AI-style markdown
|
Write concise prose. No bullet-point walls, no verbose AI-style markdown.
|
||||||
headings beyond what the template calls for. Keep it concise and human.
|
Use backticks for code references.
|
||||||
|
|
||||||
## Decomposition Rules
|
## Decomposition Rules
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# /commit
|
# /gc
|
||||||
|
|
||||||
Create a conventional commit from staged or unstaged changes.
|
Create a conventional commit from staged or unstaged changes.
|
||||||
|
|
||||||
|
|
@ -26,7 +26,10 @@ Create a conventional commit from staged or unstaged changes.
|
||||||
- Scope is optional, lowercase.
|
- Scope is optional, lowercase.
|
||||||
- Non-trivial changes require a body with `Problem:` / `Solution:` sections,
|
- Non-trivial changes require a body with `Problem:` / `Solution:` sections,
|
||||||
wrapped at 72 chars, separated from header by a blank line.
|
wrapped at 72 chars, separated from header by a blank line.
|
||||||
|
- Keep the body tight: 2-3 sentences per section, max.
|
||||||
- Trivial one-liners: header alone is fine.
|
- Trivial one-liners: header alone is fine.
|
||||||
|
- Use backticks around code identifiers, function names, and file paths
|
||||||
|
(e.g. `setup()`, `lua/pending/store.lua`).
|
||||||
- Match the style of the recent commits from step 1.
|
- Match the style of the recent commits from step 1.
|
||||||
|
|
||||||
4. Present the full message and ask for approval.
|
4. Present the full message and ask for approval.
|
||||||
51
config/claude/skills/guide/SKILL.md
Normal file
51
config/claude/skills/guide/SKILL.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# /guide
|
||||||
|
|
||||||
|
Interactive step-by-step guide for nvim plugin development tasks.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
1. Ask the user what they want to accomplish. Gather enough context to build a
|
||||||
|
step-by-step plan (the plugin name, the goal, any constraints).
|
||||||
|
|
||||||
|
2. Determine the plugin name from the current repo (basename of the working
|
||||||
|
directory) and today's date. Run exactly one Bash command:
|
||||||
|
|
||||||
|
```
|
||||||
|
basename "$(git rev-parse --show-toplevel)" && date +%Y-%m-%d
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Build a numbered step-by-step plan as a markdown file. Run exactly one Bash
|
||||||
|
command:
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p /tmp/<plugin>-<date> && cat > /tmp/<plugin>-<date>/guide.md <<'EOF'
|
||||||
|
# <Goal>
|
||||||
|
|
||||||
|
Plugin: <plugin>
|
||||||
|
Date: <date>
|
||||||
|
Branch: <branch name to create>
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. <step>
|
||||||
|
2. <step>
|
||||||
|
...
|
||||||
|
|
||||||
|
## Current
|
||||||
|
|
||||||
|
Step 1: <description>
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Present step 1 to the user. Execute it. Show the result. Ask for
|
||||||
|
confirmation before moving to the next step.
|
||||||
|
|
||||||
|
5. After the user confirms, update the `## Current` section in the guide to
|
||||||
|
reflect the next step, then execute it. Repeat until all steps are done.
|
||||||
|
|
||||||
|
6. When all steps are complete, update the guide with a `## Done` section and
|
||||||
|
print the path to the guide file.
|
||||||
|
|
||||||
|
Keep each step small and self-contained. Prefer one logical change per step.
|
||||||
|
If a step reveals unexpected complexity, break it into sub-steps and update
|
||||||
|
the guide before proceeding.
|
||||||
|
|
@ -21,28 +21,35 @@ Create a pull request from the current branch.
|
||||||
```
|
```
|
||||||
## Problem
|
## Problem
|
||||||
|
|
||||||
<why this change is needed>
|
<1-2 sentences>
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
|
|
||||||
<what the change does>
|
<1-2 sentences>
|
||||||
```
|
```
|
||||||
|
|
||||||
- Write in plain prose. No bullet walls, no AI markdown soup.
|
- Write concise prose. No bullet walls, no verbose explanations.
|
||||||
|
- Use backticks around code identifiers, function names, and file paths.
|
||||||
|
|
||||||
3. Present the title and body. Ask for approval.
|
3. Present the title and body. Ask for approval.
|
||||||
|
|
||||||
4. After approval, run exactly one Bash command (push + create chained):
|
4. After approval, if `scripts/ci.sh` exists, run it:
|
||||||
```
|
```
|
||||||
git push -u origin <branch> && gh pr create --title "<title>" --body "$(cat <<'EOF'
|
bash scripts/ci.sh
|
||||||
|
```
|
||||||
|
If it fails, show the output and stop. Do NOT create the PR.
|
||||||
|
|
||||||
|
5. Run exactly one Bash command:
|
||||||
|
```
|
||||||
|
gh pr create --title "<title>" --body "$(cat <<'EOF'
|
||||||
<body here>
|
<body here>
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
```
|
```
|
||||||
Print the PR URL from the output.
|
Print the PR URL from the output.
|
||||||
|
|
||||||
Total: 2 Bash calls (gather + push/create). Do not run any other commands. Do
|
Total: 2 Bash calls (gather + create), or 3 if CI ran. Do not run any other
|
||||||
not read files, explore code, or run additional git commands beyond what is
|
commands. Do not read files, explore code, or run additional git commands beyond
|
||||||
listed above.
|
what is listed above.
|
||||||
|
|
||||||
Never force-push, even with lease. Never target main/master as the head branch.
|
Never force-push, even with lease. Never target main/master as the head branch.
|
||||||
|
|
|
||||||
48
config/claude/skills/qpr/SKILL.md
Normal file
48
config/claude/skills/qpr/SKILL.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# /qpr
|
||||||
|
|
||||||
|
Create a pull request immediately, no approval step.
|
||||||
|
|
||||||
|
## 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. If `scripts/ci.sh` exists, run it:
|
||||||
|
```
|
||||||
|
bash scripts/ci.sh
|
||||||
|
```
|
||||||
|
If it fails, show the output and stop.
|
||||||
|
|
||||||
|
3. Draft the PR (do NOT present for approval — create it immediately):
|
||||||
|
- **Title**: `type(scope): imperative summary`, max 72 chars.
|
||||||
|
- **Body**: if a PR template was found, fill it in. Otherwise:
|
||||||
|
|
||||||
|
```
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
<1-2 sentences>
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
<1-2 sentences>
|
||||||
|
```
|
||||||
|
|
||||||
|
- Use backticks around code identifiers, function names, and file paths.
|
||||||
|
|
||||||
|
Run exactly one Bash command:
|
||||||
|
```
|
||||||
|
gh pr create --title "<title>" --body "$(cat <<'EOF'
|
||||||
|
<body here>
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
Print the PR URL from the output.
|
||||||
|
|
||||||
|
Total: 2-3 Bash calls. Do not run any other commands.
|
||||||
|
|
||||||
|
Never force-push. Never target main/master as the head branch.
|
||||||
|
|
@ -61,7 +61,7 @@ local git_status = new_git_status()
|
||||||
return {
|
return {
|
||||||
{
|
{
|
||||||
'barrettruth/midnight.nvim',
|
'barrettruth/midnight.nvim',
|
||||||
enabled = false,
|
enabled = true,
|
||||||
after = function()
|
after = function()
|
||||||
vim.cmd.colorscheme('midnight')
|
vim.cmd.colorscheme('midnight')
|
||||||
end,
|
end,
|
||||||
|
|
@ -300,6 +300,6 @@ return {
|
||||||
latex = { open = { 'sioyek', '--new-instance' } },
|
latex = { open = { 'sioyek', '--new-instance' } },
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
keys = { { '<leader>p', '<cmd>Preview toggle<cr>' } },
|
keys = { { '<leader>p', '<cmd>Preview watch<cr>' } },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,12 +225,14 @@ end)
|
||||||
return {
|
return {
|
||||||
{
|
{
|
||||||
'barrettruth/diffs.nvim',
|
'barrettruth/diffs.nvim',
|
||||||
|
enabled = true,
|
||||||
before = function()
|
before = function()
|
||||||
vim.g.diffs = {
|
vim.g.diffs = {
|
||||||
|
debug = '/tmp/diffs.log',
|
||||||
fugitive = true,
|
fugitive = true,
|
||||||
neogit = false,
|
neogit = false,
|
||||||
extra_filetypes = { 'diff' },
|
extra_filetypes = { 'diff' },
|
||||||
hide_prefix = true,
|
hide_prefix = false,
|
||||||
highlights = {
|
highlights = {
|
||||||
vim = {
|
vim = {
|
||||||
enabled = true,
|
enabled = true,
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,19 @@ in
|
||||||
"api.github.com"
|
"api.github.com"
|
||||||
];
|
];
|
||||||
tools.web_fetch = true;
|
tools.web_fetch = true;
|
||||||
|
hooks = {
|
||||||
|
PreToolUse = [
|
||||||
|
{
|
||||||
|
matcher = "Bash";
|
||||||
|
hooks = [
|
||||||
|
{
|
||||||
|
type = "command";
|
||||||
|
command = "${config.xdg.configHome}/claude/hooks/guard.sh";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -369,6 +382,10 @@ in
|
||||||
source = config.lib.file.mkOutOfStoreSymlink "${repoDir}/config/claude/skills";
|
source = config.lib.file.mkOutOfStoreSymlink "${repoDir}/config/claude/skills";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.configFile."claude/hooks" = lib.mkIf claude {
|
||||||
|
source = config.lib.file.mkOutOfStoreSymlink "${repoDir}/config/claude/hooks";
|
||||||
|
};
|
||||||
|
|
||||||
xdg.configFile."tmux/themes/midnight.conf".source =
|
xdg.configFile."tmux/themes/midnight.conf".source =
|
||||||
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.config/nix/config/tmux/themes/midnight.conf";
|
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.config/nix/config/tmux/themes/midnight.conf";
|
||||||
xdg.configFile."tmux/themes/daylight.conf".source =
|
xdg.configFile."tmux/themes/daylight.conf".source =
|
||||||
|
|
|
||||||
10
scripts/mux
10
scripts/mux
|
|
@ -145,7 +145,7 @@ ai)
|
||||||
;;
|
;;
|
||||||
code)
|
code)
|
||||||
require nvim
|
require nvim
|
||||||
spawn_or_focus code 'nvim -c "lua require([[config.tmux]]).run([[nvim]])"'
|
spawn_or_focus code 'nvim .'
|
||||||
;;
|
;;
|
||||||
git)
|
git)
|
||||||
require nvim git
|
require nvim git
|
||||||
|
|
@ -153,13 +153,9 @@ git)
|
||||||
if ! git -C "$pane_path" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
if ! git -C "$pane_path" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
tmux display-message "Not a git repository"
|
tmux display-message "Not a git repository"
|
||||||
else
|
else
|
||||||
spawn_or_focus git 'nvim -c "lua require([[config.tmux]]).run([[git]])"'
|
spawn_or_focus git 'nvim -c "Git|only"'
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
run)
|
|
||||||
require nvim
|
|
||||||
spawn_or_focus run 'nvim -c "lua require([[config.tmux]]).run([[run]])"'
|
|
||||||
;;
|
|
||||||
shell)
|
shell)
|
||||||
spawn_or_focus shell
|
spawn_or_focus shell
|
||||||
;;
|
;;
|
||||||
|
|
@ -178,7 +174,7 @@ cmd)
|
||||||
action=$(printf '%s' "$result" | sed -n '2p')
|
action=$(printf '%s' "$result" | sed -n '2p')
|
||||||
[ $rc -eq 130 ] && exit
|
[ $rc -eq 130 ] && exit
|
||||||
if [ -n "$query" ] && [ "$query" != "$action" ]; then
|
if [ -n "$query" ] && [ "$query" != "$action" ]; then
|
||||||
tmux $query
|
tmux "$query"
|
||||||
elif [ -n "$action" ]; then
|
elif [ -n "$action" ]; then
|
||||||
case "$action" in
|
case "$action" in
|
||||||
switch-client) pick_session ;;
|
switch-client) pick_session ;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue