| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
The SessionStart hook joined host and project with a space ("ratio rulesets"), which reads as two words in the claude.ai/code and mobile session lists. I changed the join to "$host-$project" ("ratio-rulesets") so the title is one token, and updated the three session-title-hook.bats expectations test-first.
|
| |
|
|
|
|
|
|
| |
Remote sessions showed up on claude.ai/code and mobile under auto-generated names, so picking the right one meant guessing. Claude Code 2.1.152+ lets a SessionStart hook set the title via hookSpecificOutput.sessionTitle.
hooks/session-title.sh emits "<uname -n> <project>" (ratio rulesets, velox work) on startup and resume. Project is the git-toplevel basename so a session started in a subdirectory still names the project, with the cwd basename as fallback. The hook stays silent when a title already exists, so a /rename or an earlier run isn't clobbered on resume. The harness ignores titles on clear and compact, so the settings matcher restricts to startup|resume.
Wired in settings.json and the install-hooks snippet. As a default hook it reaches every machine through make install on the next session start.
|
| |
|
|
|
|
| |
On a flush resume, the SessionStart(clear) hook now reads .ai/notes.org key sections before the session-context anchor. The anchor carries session state. notes.org carries the project's standing knowledge (code-repo paths, conventions, key contacts) that a resumed session needs to act correctly. A resume with the anchor alone floundered on context notes.org already documents, hunting for a repo whose path notes.org records.
The hook guards on notes.org presence: when it's absent, the resume reads the anchor alone. flush/SKILL.md documents the same read order so the skill and the hook agree. The handoff rationale is preserved in docs/design/2026-06-02-flush-promotion.org.
|
| |
|
|
|
|
|
|
|
|
| |
Flush is the checkpoint half of the wrap/restart rhythm. It refreshes the session-context anchor in place, the user runs /clear, and the session resumes from the anchor instead of starting cold. One logical session stays alive across a /clear boundary without the archive-and-commit of wrap-it-up or the full cold boot of startup, which buys cheaper tokens and a sharper context window.
The mechanism splits into two halves around /clear, which wipes the conversation so nothing runs straight through it. The /flush skill is the pre-clear half: dump live state, refresh the anchor's Summary, append a dated flush marker, verify the write landed, then prompt the user to /clear. The agent can initiate at a clean task boundary on its own judgment, but /clear is user-only, so the agent does the work and the user supplies the single keystroke. The session-clear-resume.sh hook is the post-clear half, a SessionStart matcher=clear hook that points the fresh session at the anchor to resume, or at startup when no anchor exists.
I packaged the pre-clear half as a skill rather than a project-workflow doc so both halves are global. The hook was already global, so /flush is now callable by name from any project with no per-project sync.
The hook is canonicalized under hooks/ and symlinked into ~/.claude/hooks/, matching precompact-priorities.sh. settings.json wires the SessionStart entry, and settings-snippet.json carries it so a fresh machine wires the hook on make install-hooks.
|
| |
|
|
|
|
|
|
|
|
| |
Two audit gaps in the confirmation hooks, plus the test harness they were missing.
The git-commit and gh-pr-create hooks scanned for AI attribution but only saw inline messages. A commit made with -F/--file or a PR made with --body-file slipped through, since the hook stored a placeholder instead of the file's text, and the publish flow uses -F constantly. A new read_referenced_file helper in _common.py reads the referenced local file (missing, oversized, or non-UTF-8 returns None, which means "couldn't inspect" and never "clean"), so attribution scanning now sees the real committed and posted text. An unreadable file falls through to the existing ask-anyway path.
destructive-bash-confirm.py parsed rm flags by splitting on whitespace, which mangled quoted paths and missed flag variants. detect_rm_rf now tokenizes with shlex, so quoted or spaced paths and combined, separate, or reordered flags all parse. It fails toward asking (a sentinel that still fires the modal) on unbalanced quotes, or when a forced recursive rm sits alongside a pipeline, compound command, substitution, or redirect, since target attribution isn't trustworthy there. The supported and unsupported shell constructs are documented in the docstrings.
These hooks had no tests and weren't in make test. Added a pytest harness under hooks/tests (an importlib-by-path loader, since the hook filenames are hyphenated) with 54 tests across the three hooks and the shared helper, and wired hooks/tests into make test. Full suite green.
|
| |
|
|
| |
The README's manual-install and settings-JSON snippets omitted destructive-bash-confirm.py, while the canonical hooks/settings-snippet.json already wires all three. Brought the README in line: added the opt-in symlink step, added the settings entry, and reworded the note so all three read as no-op-safe with the destructive gate flagged as opt-in (make install-hooks excludes it by default).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The hook used to emit a confirmation modal on every git commit. That
produced too many benign interruptions — the modal fired even on clean,
well-formed, attribution-free commits. Now it only emits a modal when
one of these safety checks fires:
- AI-attribution patterns in the commit message (Co-Authored-By: Claude,
robot emoji, Generated-with-AI footers, etc.) — the primary leak
- Message not parseable from command line (editor would open, which
silently blocks Claude)
- No files staged (the commit would fail anyway)
- Git author unusable (user.name / user.email not configured)
Clean commits pass through silent. The AI-attribution scan is unchanged;
the always-on review is gone.
README updated to describe the new behavior.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
problem-solving routing
Three improvements bundled together:
1. New hook — `destructive-bash-confirm.py` (PreToolUse/Bash):
Gates `git push --force`, `git reset --hard`, `git clean -f`,
`git branch -D`, and `rm -rf` behind a confirmation modal with the
command, local context (branch, uncommitted counts, targeted paths),
and a severity banner. Elevates severity when force-pushing protected
branches (main/master/develop/release/prod) or when rm -rf targets
root, home, or wildcard paths. Reuses _common.py.
2. Architecture suite rename — the "Part of the arch-* suite" footer in
arch-design, arch-decide, arch-document, arch-evaluate descriptions
now reads "Part of the architecture suite (arch-design / arch-decide
/ arch-document / arch-evaluate + c4-analyze / c4-diagram for
notation-specific diagramming)." Matching footers added to c4-analyze
and c4-diagram. c4-* keep their framework-specific prefix (C4 is a
notation, arch-* is framework-agnostic workflow) but are now
discoverable as suite members.
3. Problem-solving cluster routing — added YAML frontmatter with
descriptions (including "Do NOT use for X (use Y)" clauses) to
debug/SKILL.md and fix-issue/SKILL.md. Previously both had no
frontmatter at all, which broke skill-router discovery. The four
cluster members (debug, fix-issue, root-cause-trace, five-whys) now
route unambiguously by description alone.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Consolidates stdin-parse and response-emit across the two confirm hooks
into `hooks/_common.py` (stdlib-only, sibling symlinked alongside the
hooks it serves). Net ~28 lines less duplication.
Adds a `systemMessage` banner alongside the confirmation modal when the
commit message or PR title/body contains AI-attribution patterns:
- Co-Authored-By: Claude|Anthropic|GPT|AI trailers
- 🤖 robot emoji
- "Generated with Claude Code" / similar footers
- "Created with …" / "Assisted by …" variants
Scanning targets structural leak patterns only — bare mentions of
"Claude" or "Anthropic" in diff context don't fire, so discussing the
tools themselves in a commit message doesn't false-positive.
Clean-room synthesis from GowayLee/cchooks (MIT) — specifically, the
systemMessage-alongside-reason pattern and event-aware stdin helpers.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three new machine-wide hooks installed via `make install-hooks`:
- `precompact-priorities.sh` (PreCompact) — injects a priority block into
the compaction prompt so the generated summary retains information most
expensive to reconstruct: unanswered questions, root causes with
file:line, subagent findings as primary evidence, exact numbers/IDs,
A-vs-B decisions, open TODOs, classified-data handling.
- `git-commit-confirm.py` (PreToolUse/Bash) — gates `git commit` behind a
confirmation modal showing parsed message, staged files, diff stats,
author. Parses both HEREDOC and `-m`/`--message` forms.
- `gh-pr-create-confirm.py` (PreToolUse/Bash) — gates `gh pr create`
behind a modal showing title, base ← head, reviewers, labels,
assignees, milestone, draft flag, body (HEREDOC or quoted).
Makefile: adds `install-hooks` / `uninstall-hooks` targets and extends
`list` with a Hooks section. Install prints the settings.json snippet
(in `hooks/settings-snippet.json`) to merge into `~/.claude/settings.json`.
Also: `languages/elisp/claude/hooks/validate-el.sh` now emits JSON with
`hookSpecificOutput.additionalContext` on failure (via new `fail_json()`
helper) so Claude sees a structured error in context, in addition to
the existing stderr output and exit 2.
Patterns synthesized clean-room from fcakyon/claude-codex-settings
(Apache-2.0). Each hook is original content.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The hooks/settings.json template was broken since day one:
- PostEditTool is not a valid Claude hook event
- PreCommit is not a Claude concept at all
- matcher was used as a glob, not a tool-name regex
- $FILE was never substituted from stdin JSON
Hooks never fired. Formatting and secret-scanning belong in CI and
pre-commit frameworks, not per-developer Claude config. Remove the
template and its install-hooks Makefile target.
|
|
|
Hooks provide:
- PostEditTool: ruff format/check on Python, terraform fmt on .tf
- PreCommit: block commits containing hardcoded secrets (AWS keys, API tokens, passwords)
Install per-project with: make install-hooks TARGET=/path/to/project
Won't overwrite existing settings.json — shows diff command instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|