Skip to content

feat(hooks): add SessionEnd progress logger and local progress tracker#87

Open
DhanyaJose wants to merge 2 commits intoluongnv89:mainfrom
DhanyaJose:feat/session-end-hook-progress-tracker
Open

feat(hooks): add SessionEnd progress logger and local progress tracker#87
DhanyaJose wants to merge 2 commits intoluongnv89:mainfrom
DhanyaJose:feat/session-end-hook-progress-tracker

Conversation

@DhanyaJose
Copy link
Copy Markdown

@DhanyaJose DhanyaJose commented Apr 19, 2026

Summary

  • New hook 06-hooks/session-end.sh — fires on SessionEnd (once per session, not after every response), prompts for modules studied, and appends a record to ~/.claude-howto-progress.json outside the repo so progress survives git pull
  • New file local-progress/index.html — self-contained visual tracker with checkboxes for all 10 modules, per-module notes, overall progress bar, and Export/Import JSON backup
  • Updated 06-hooks/README.md — Example 8 documents the hook with a patterns table and pointer to the HTML tracker
  • Updated .gitignorelocal-progress/local-progress/*.json so the HTML ships but exported data files stay local

Why this is useful

The repo's existing progress tracking (checklists in LEARNING-ROADMAP.md, /self-assessment skill) lives inside repo files — a git pull overwrites any marks made there. This contribution stores progress outside the repo permanently.

Key patterns demonstrated by the hook

Pattern Why it matters
SessionEnd event Fires once on exit — not after every response like Stop
read -r INPUT </dev/tty Hooks own stdin (JSON payload); use /dev/tty for user input
$CLAUDE_PROJECT_DIR Portable path — never hardcode /Users/yourname/...
Guard clause at top Prevents the hook running in unrelated projects if installed globally

Test plan

  • open local-progress/index.html — 10 modules render with checkboxes and progress bar
  • Check a box, refresh — checkbox persists (localStorage)
  • Export JSON — file downloads with correct structure
  • Import JSON — progress restores from file
  • Install hook via .claude/settings.json, end a session — record appended to ~/.claude-howto-progress.json
  • git statuslocal-progress/*.json ignored, index.html tracked

🤖 Generated with Claude Code

Adds a SessionEnd hook that prompts for modules studied at session end
and appends a record to ~/.claude-howto-progress.json — outside the repo
so progress survives git pull without being overwritten.

Also adds local-progress/index.html: a self-contained visual tracker
with checkboxes for all 10 modules, per-module notes, an overall progress
bar, and Export/Import to sync with a local JSON backup file.

Key patterns demonstrated:
- SessionEnd vs Stop (fires once on exit, not after every response)
- /dev/tty for interactive input in hooks (stdin carries the JSON payload)
- $CLAUDE_PROJECT_DIR for portable paths (never hardcode /Users/...)
- Guard clause to prevent global hook running in unrelated projects

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@luongnv89
Copy link
Copy Markdown
Owner

Thanks for this — the SessionEnd hook + HTML tracker is a really nice addition! 🎯 Reviewed the changes and CI is green, but I caught a few things worth fixing before merge:

🔴 Bash 3.2 parse error (macOS default)

session-end.sh fails to parse on macOS's system bash (3.2):

$ bash -n 06-hooks/session-end.sh
06-hooks/session-end.sh: line 47: syntax error near unexpected token `;;'

The case inside $(... | while read; do ... done | ...) is a known bash 3.2 quirk. CI passes because Linux runners use bash 5. Many macOS users will hit this.

Fix: replace the pipeline+while with a for loop over IFS=',' array — keeps the same behavior, parses on bash 3.2+. Same fix needed in the README copy (lines 980–994).

🟡 Notes with " break the JSON

session-end.sh:64 builds JSON via shell interpolation:

SESSION="{...,\"notes\":\"${NOTES}\"}"

A note like tried "case in subshell" produces invalid JSON and json.loads throws — session goes unrecorded. Fix: pass $NOTES as a separate argv to the Python heredoc and let Python build the JSON.

🟡 XSS via Import in local-progress/index.html

render() at line 561 puts saved notes into the DOM via innerHTML:

<textarea >${modState.notes || ''}</textarea>

A crafted imported JSON with </textarea><script>… breaks out. Fix: set textarea.value after creating the element, or use textContent.


Everything else looks great — diagrams render, cross-refs valid, mermaid clean (216 diagrams), tests pass. Happy to help iterate on the fix if useful 🙏

…rea XSS

  - Replace pipeline+while with IFS for-loop (bash 3.2 compatible)
  - Pass NOTES as Python arg to avoid broken JSON on quotes/backslashes
  - Set textarea.value instead of innerHTML to prevent XSS from imported JSON
  Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@DhanyaJose DhanyaJose force-pushed the feat/session-end-hook-progress-tracker branch from 7059d3a to 01dc280 Compare April 25, 2026 07:09
Copy link
Copy Markdown
Author

@DhanyaJose DhanyaJose left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @luongnv89 for your review #87 (comment). I have incorporated your comments with the help of Claude. Please review these changes.

Thank you for creating this repository, this helps a lot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants