Repository navigation
feat(hooks): index skill usage by project and session - #25
Merged
Merged
Conversation
Skill records took the cwd from the hook payload without undoing its JSON escaping, so every backslash in C:\Users became a doubled forward slash. Session records took $PWD, which Git Bash spells /d/x or, under a mount, /tmp/x. The real log carried the same project under both spellings, so usage could not be grouped by project. The shared writer now canonicalizes every path: Windows paths become C:/x, and MSYS paths go through cygpath, the only thing that knows where a mount such as /tmp points. POSIX hosts are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The log could say which skills fired but not where, or from which conversation. skills-count.sh now breaks skill invocations down by project. Records written before the path fix doubled every separator, so the report folds them onto the current spelling and an existing log stays comparable with new records. Skill records also carry the host's session_id. It is the only pointer from a suspicious trigger back to the transcript that produced it, which is where a false-trigger report has to start. The field is appended last so existing readers of the record keep working. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
States that usage stays attributable to a project after the project is deleted, and that the summary breaks down by host, skill, and project and accepts a keyword to narrow it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
log-usage now decodes the payload, so a skill name or session id can hold a real backslash. The writer escaped only quotes: odd\name was logged as a newline, and a trailing backslash swallowed the closing quote and broke the whole record. Found reviewing this branch; directory names are unaffected because canonical paths carry no backslashes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Per-project usage and session ids on skill records are a new capability, so this is a minor bump. No skill behavior changes and the fixed-context baseline is untouched at 4580. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The usage log exists to show where skills fire, and on Windows it could not.
Skill records took
cwdfrom the hook payload without undoing its JSON escaping,so
C:\Userswas logged asC://Users. Session records took Git Bash's$PWD,which reads
/c/Users, or/tmp/...under a mount. The same project sat undertwo spellings,
skills-count.shhad no per-project view, and nothing tied a skillrecord back to the conversation that produced it.
Checked against a real log (2,474 records since 2026-07): every Windows project
was split this way, and 73 of the 182 skill records came from one
claude plugin evalscratch directory, which stayed invisible until usage isbroken down by project.
What changed
become
C:/x; MSYS paths go throughcygpath, the only thing that knows wherea mount such as
/tmppoints. POSIX hosts are unchanged.session_id, appended last soexisting readers keep working.
skills-count.shbreaks skill invocations downby project and folds records written before the fix onto the current spelling,
so an existing log stays comparable with new records.
skillandsession_id, and the writer escaped only quotes, soodd\namewas logged as a newline and a trailing backslash broke the record. The writer
now escapes backslashes before quotes.
No skill text, primer, or fixed-context change. The sink is still
~/.coding-discipline/usage.jsonl.Version
Ships as v0.10.0. v0.9.0 was tagged and released from
main(f45a6a2) first,so its frozen scope stays intact; this branch is a minor bump because
per-project usage and session ids are a new capability.
Verification
Written test-first. Each new case failed on the old code for the real reason
before passing: the payload case logged
"cwd":"C://Users//dev//proj", onWindows one directory came out as
/tmp/.../repoandC://Users//...//repo,and the review case produced a record that
json.loadsrejects.Review probes beyond the suites: a directory named with Chinese characters and a
space, run both through Git Bash directly and through
cmd.exeandrun-hook.cmd, produced one spelling and valid UTF-8 for session and skillrecords alike.
All four suites pass locally on
35e39d9: plugin metadata, the safety scan, thehook suite under Git Bash, and the Windows suite, which drives
log-usagethrough
run-hook.cmdthe way Claude Code does on Windows. Run read-only againstthe real log, the new section prints one line per project with pre-fix and
post-fix records merged.
Notes:
/d/...spelling. The report only foldsskill records, because the per-project view counts skill invocations.
cygpathprocess. Acceptablefor a once-per-session hook; noted in case startup time ever matters.
🤖 Generated with Claude Code