[Sync] llm stuff

This commit is contained in:
Coja
2026-09-17 20:58:21 +02:00
parent ed7e34552d
commit d8f6b30e2c
52 changed files with 2233 additions and 237 deletions
@@ -2,7 +2,7 @@
description: Draft a commit message for the staged changes, matching this repo's commit style, then print it in the reply, save it to the repo's CLAUDE_COMMIT_MSG file, and copy it to the clipboard. Never stages or commits. Use once you've staged what you want to commit.
argument-hint: [optional focus/scope hint]
disable-model-invocation: true
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git rev-parse:*), Bash(wl-copy:*), Read, Glob, Write
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git rev-parse:*), Bash(wl-copy:*), Bash(~/.config/git/claude-commit-msg:*), Read, Glob
---
# Draft a commit message for the staged changes
@@ -29,14 +29,20 @@ Context for the current commit — what's staged, plus this repo's recent style:
ready. This in-reply copy is the durable one: it lives in the transcript, so it survives even if
the clipboard gets overwritten later (by me copying something else, or another Claude session
running `wl-copy`). Always print it; don't rely on the clipboard alone.
5. **Save it to a file in the repo** so I can recover it any time: resolve the path with
`git rev-parse --git-path CLAUDE_COMMIT_MSG` (per-worktree correct), then use the Write tool to
write the raw message there — **not** `COMMIT_EDITMSG`, which git overwrites on every
`git commit` before the editor opens. My `prepare-commit-msg` hook prefills the commit editor
from `CLAUDE_COMMIT_MSG` (one-shot) on the next `git commit` / lazygit `C`. The file lives
inside the git dir so it never shows up in `git status`.
6. **Also copy it to the clipboard** as a convenience: `wl-copy < <path from step 5>`. Then
tell me all three places it is: **printed above**, **saved to `CLAUDE_COMMIT_MSG`** (hook
prefills the next commit), and **on the clipboard** — so I never lose it to a stray copy.
5. **Hand it off** so I can recover it any time — feed the raw message to the CLI as a quoted
heredoc (so quotes, backticks and `$` in the body survive untouched):
```sh
~/.config/git/claude-commit-msg save <<'EOF'
<message>
EOF
```
That stores it as its own file under `$(git rev-parse --git-path CLAUDE_COMMIT_MSG.d)/` **together with the staged paths
it describes**, so several sessions can hand off in parallel without overwriting each other. My
`prepare-commit-msg` hook prefills the next `git commit` / lazygit `C` with the message(s) whose
paths are part of that commit, then consumes them. Never write `CLAUDE_COMMIT_MSG` or
`COMMIT_EDITMSG` directly. The `save` output names the saved id and file path.
6. **Also copy it to the clipboard** as a convenience: `wl-copy < <file path printed by save>`.
Then tell me all three places it is: **printed above**, **saved for the hook** (with its id),
and **on the clipboard** — so I never lose it to a stray copy.
7. **Never** run `git add`, `git commit`, or `git push`, and never offer to — I stage and commit
manually. Draft only.
+19 -14
View File
@@ -2,7 +2,7 @@
description: Babysit the current branch's PR — address review comments that don't need my input, re-check every ~10 min, and stop when there are no open comments left or the automated reviewers (Codex, Claude) hit their limit. Prep-only — stages fixes and drafts the commit message; never commits, pushes, or merges.
argument-hint: [pr number or url — optional; defaults to the current branch's PR]
disable-model-invocation: true
allowed-tools: Bash(gh:*), Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git rev-parse:*), Bash(git fetch:*), Bash(git add:*), Bash(wl-copy:*), Read, Edit, Write, Grep, Glob, ScheduleWakeup
allowed-tools: Bash(gh:*), Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git rev-parse:*), Bash(git fetch:*), Bash(git add:*), Bash(wl-copy:*), Bash(~/.config/git/claude-commit-msg:*), Read, Edit, Write, Grep, Glob, ScheduleWakeup
---
# Watch this PR and resolve review comments (prep-only)
@@ -36,11 +36,12 @@ comments left or the automated reviewers (Codex/Claude) hit a usage limit.
session stays open**. **To stop it: press `Esc` while I'm idle between cycles** (that clears the
queued wake-up); closing the session also stops it. A plain message does **not** cancel a pending
wake-up — use `Esc`.
- **Every token counts.** Each wake-up re-reads the whole conversation with a cold prompt cache
(the 10-min cadence outlives the 5-min cache TTL), so cost compounds with every cycle and every
extra line in context. Therefore: fetch **filtered** data only (use the `--jq` filters below —
never let raw unfiltered JSON into the conversation), summarize deltas rather than restating
unchanged state, and keep idle cycles to **one cheap API call and ≤2 lines of output**.
- **Every token counts.** Each wake-up re-sends the whole conversation. On a Claude subscription
the prompt cache holds for **1 hour**, so the 10-min cadence stays warm; on an API key it drops to
5 min and every cycle is a cold read. Either way every extra line in context rides along on every
later cycle. Therefore: fetch **filtered** data only (use the `--jq` filters below — never let raw
unfiltered JSON into the conversation), summarize deltas rather than restating unchanged state,
and keep idle cycles to **one cheap API call and ≤2 lines of output**.
Current state (auth + the current branch's PR):
@@ -233,10 +234,11 @@ Current state (auth + the current branch's PR):
9. **Draft the commit message — exactly like `/commit-msg`:** from the staged diff and the repo's
recent `git log` style (this repo uses `[Scope] summary`), write a message that matches. Then:
- **(a) Print it** in your reply as a fenced ` ```text ` block — the durable copy.
- **(b) Write it** with the Write tool to the path from `git rev-parse --git-path CLAUDE_COMMIT_MSG`
(**not** `COMMIT_EDITMSG`git overwrites that on `git commit`; the `prepare-commit-msg` hook
prefills the editor from `CLAUDE_COMMIT_MSG`).
- **(c) Copy it:** `wl-copy < <that path>`.
- **(b) Hand it off:** `~/.config/git/claude-commit-msg save <<'EOF'``EOF` (the message as a
quoted heredoc, so quotes and backticks survive) — it is stored with the paths you staged this cycle, so the `prepare-commit-msg` hook prefills it only
for the commit that contains them (other sessions' handoffs are not overwritten). Never write
`CLAUDE_COMMIT_MSG` / `COMMIT_EDITMSG` directly.
- **(c) Copy it:** `wl-copy < <file path printed by save>`.
- Tell me all three locations. **Never** run `git commit`.
(Skip this step when nothing new was staged this cycle.)
@@ -252,9 +254,10 @@ Current state (auth + the current branch's PR):
needs-input questions are posted (reactions don't bump `updatedAt`, comments do — so your own
activity doesn't defeat the next cheap check), then save state
to `<git-dir>/pr-loop-state.json`. Then schedule:
- **normal cycle:** `ScheduleWakeup(delaySeconds=600, prompt="/pr-loop", reason="recheck PR
#<num> review comments")`;
- **idle cycle** (step 3 short-circuited): back off — `delaySeconds=1200`, I'm clearly away;
- **normal cycle:** `ScheduleWakeup(delaySeconds=600, noop=false, prompt="/pr-loop",
reason="recheck PR #<num> review comments")`;
- **idle cycle** (step 3 short-circuited): back off — `delaySeconds=1200, noop=true` (idle
ticks then collapse into one line in my terminal instead of stacking), I'm clearly away;
re-running `/pr-loop` checks immediately.
End the turn with a sign-off that states when you'll run again and how to stop, e.g.:
@@ -268,7 +271,9 @@ Current state (auth + the current branch's PR):
- **Never** `git commit`, `git push`, `gh pr merge`, `gh pr create`, `gh pr close`, or `gh pr edit`
— I do all of those. You stage, react, resolve, and draft; nothing more. The only comment you may
post is a needs-input decision question.
post is a needs-input decision question. This is enforced, not just asked: `settings.json` denies
those commands and the `git-guard.py` PreToolUse hook blocks any spelling of them, so a slip is
refused with a reason rather than executed.
- Act only on the target PR. Don't touch unrelated files or other PRs.
- **Keep context lean:** no raw JSON dumps in replies, no re-listing threads that haven't changed,
idle cycles ≤2 lines. Every line you emit is re-read (uncached) on every later cycle.
@@ -2,7 +2,7 @@
description: Review all changes on the current branch (diff vs its base) for bugs, security issues, optimizations, and readability/scannability, then apply the readability + safe improvements after you approve. Use right before opening a PR.
argument-hint: [base-branch]
disable-model-invocation: true
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git merge-base:*), Bash(git symbolic-ref:*), Bash(git rev-parse:*), Bash(git show-ref:*), Bash(git branch:*), Read, Grep, Glob
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git merge-base:*), Bash(git symbolic-ref:*), Bash(git rev-parse:*), Bash(git show-ref:*), Bash(git branch:*), Read, Grep, Glob, Edit, Write
---
# Review this branch
@@ -59,11 +59,10 @@ Context auto-collected for the current branch vs. its base:
surfaced, not a blanket dump. Only include the ones that actually fit:
- `/security-review` — a deeper, whole-branch security pass; suggest whenever the 🔒 lens
flagged something or the diff touches auth, crypto, input handling, secrets, or network I/O.
- `/code-review` (add `--fix` to apply, `--comment` for inline PR comments) — a second review
of the working-tree diff at a chosen effort level.
- `/code-review` (alias `/review`; add `--fix` to apply, `--comment` for inline PR comments) —
a second review of the working-tree diff, a PR number or a branch at a chosen effort level.
- `/simplify` — apply reuse / simplification / efficiency cleanups beyond the safe ones applied
here.
- `/verify` — run the app to confirm the change behaves, if this branch changed behavior.
- `/pr-description` — draft the PR text from this branch once the review is clean.
- `/review` — review the PR on GitHub after it's open.
8. **Never** run `git commit` or `git push` — I do that manually.
@@ -0,0 +1,20 @@
---
description: Toggle the persisted verbose view for this project (viewMode verbose/default, plus verbose + showThinkingSummaries) by writing .claude/settings.local.json, and print the live-view keybind. Usage: /verbose [on|off|status]; no argument toggles. Runs TUI-side via the UserPromptExpansion hook; this body is only the fallback.
argument-hint: [on|off|status]
disable-model-invocation: true
allowed-tools: Bash(python3:*)
---
# /verbose (fallback path)
Normally you never see this: `hooks/local-commands.py` (UserPromptExpansion) runs
`skills/verbose/local.py` and blocks the expansion, so `/verbose` costs no model turn. This body
only loads on a host where that hook isn't deployed yet.
Run exactly this, then relay its output to me verbatim in a fenced ```text block with **at most one
line** of your own:
python3 ~/.claude/skills/verbose/local.py $ARGUMENTS
Don't edit any settings file yourself, don't run anything else, and don't offer follow-ups. If it
reports an error, quote it and stop.
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""`/verbose`, TUI-side: flip Claude Code's *persisted* verbose view for the current project.
Run by hooks/local-commands.py from the UserPromptExpansion hook, i.e. when you type
`/verbose [on|off|status]` -- the hook executes this and blocks the skill expansion, so no
prompt ever reaches the model and the output below is shown to you directly. (On a host
without that hook, skills/verbose/SKILL.md falls back to having the model run it.)
Claude Code has no built-in runtime `/verbose`; the live toggle is a keypress (`ctrl+x v`
here, `ctrl+o` by default -- `app:toggleTranscript`). What can be scripted is the persisted
default: `viewMode` ("verbose" | "default" | "focus" -- this is what actually decides the view;
it also beats a sticky `/focus` choice for new sessions), plus `verbose` (full tool
input/output inline) and `showThinkingSummaries` for versions without viewMode. All accept any
settings scope, so this writes the project's
`.claude/settings.local.json` -- local to this machine, never committed -- instead of the
dots-tracked ~/.claude/settings.json, which would show a diff on every toggle. Project-local
settings win over user settings, so the user default stays `verbose: true` and a project can
be quietened individually.
usage: local.py [on|off|toggle|status] (no argument = toggle)
"""
import json
import os
import subprocess
import sys
KEYS = ("verbose", "showThinkingSummaries")
VIEW = "viewMode" # "verbose" | "default" | "focus"; overrides KEYS and the sticky /focus choice
LIVE = "live view: ctrl+x v (or ctrl+o) toggles the transcript; ctrl+e inside it shows everything"
def project_root():
try:
r = subprocess.run(["git", "rev-parse", "--show-toplevel"], capture_output=True, text=True, timeout=2)
if r.returncode == 0 and r.stdout.strip():
return r.stdout.strip()
except Exception:
pass
return os.getcwd()
def load(path):
try:
with open(path) as fh:
return json.load(fh)
except FileNotFoundError:
return {}
except Exception as e: # a broken local file must not be silently overwritten
sys.exit(f"error: cannot parse {path}: {e}")
def main():
raw = " ".join(sys.argv[1:]).strip()
mode = raw.lower() or "toggle"
if mode not in ("on", "off", "toggle", "status"):
sys.exit("usage: /verbose [on|off|status]")
root = project_root()
local_path = os.path.join(root, ".claude", "settings.local.json")
user = load(os.path.expanduser("~/.claude/settings.json"))
local = load(local_path)
effective = {k: bool(local.get(k, user.get(k, False))) for k in KEYS}
view = local.get(VIEW, user.get(VIEW))
def state_of(view, eff):
if view == "verbose":
return "ON"
if view in ("default", "focus"):
return f"OFF ({view} forced by settings)"
if all(eff.values()):
return "ON via the verbose key (viewMode unset: a sticky /focus choice still wins)"
return "OFF" if not any(eff.values()) else "MIXED"
if mode != "status":
current_on = state_of(view, effective).startswith("ON")
on = {"on": True, "off": False}.get(mode, not current_on)
if on:
local[VIEW] = "verbose" # forces verbose for new sessions, beating a sticky /focus
else:
local.pop(VIEW, None) # release: the sticky /focus choice (or default) applies again
for k in KEYS:
local[k] = on
os.makedirs(os.path.dirname(local_path), exist_ok=True)
with open(local_path, "w") as fh:
json.dump(local, fh, indent=2)
fh.write("\n")
effective = {k: on for k in KEYS}
view = local.get(VIEW, user.get(VIEW))
print(f"verbose view: {'ON' if on else 'OFF'} for {root}")
print(f" written to {local_path} (viewMode applies to new sessions; the current one: ctrl+x v)")
else:
print(f"verbose view: {state_of(view, effective)} for {root}")
print(f" {VIEW}: {view or '-'} (project-local: {local.get(VIEW, '-')}, user: {user.get(VIEW, '-')})")
for k in KEYS:
print(f" {k}: {str(effective[k]).lower()} (project-local: {local.get(k, '-')}, user: {user.get(k, '-')})")
print(LIVE)
if __name__ == "__main__":
main()