Stats
Actions
Tags
Help us improve
Share bugs, ideas, or general feedback.
Monitors and enforces writing quality on every file edit with lint checks, prose validation, and citation fidelity. Blocks image Read calls and suggests compact on large edits. Runs Python scripts via UV on all major session events.
6 events · 15 hooks
npx claudepluginhub codelably/harmony-claude-codeSafety signals detected in this hook configuration
Where this hook configuration is defined
Defined in hooks/hooks.json
Event handlers and matchers — expand Raw Configuration for the full JSON
*node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/check-console-log.js"*node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pre-compact.js"tool == "Bash" && tool_input.command matches "(npm run dev|pnpm( run)? dev|yarn dev|bun run dev)"node -e "console.error('[Hook] BLOCKED: Dev server must run in tmux for log access');console.error('[Hook] Use: tmux new-session -d -s dev \"npm run dev\"');console.error('[Hook] Then: tmux attach -t dev');process.exit(1)"tool == "Bash" && tool_input.command matches "(npm (install|test)|pnpm (install|test)|yarn (install|test)?|bun (install|test)|cargo build|make|docker|pytest|vitest|playwright)"node -e "if(!process.env.TMUX){console.error('[Hook] Consider running in tmux for session persistence');console.error('[Hook] tmux new -s dev | tmux attach -t dev')}"tool == "Bash" && tool_input.command matches "git push"node -e "console.error('[Hook] Review changes before push...');console.error('[Hook] Continuing with push (remove this hook to add interactive review)')"tool == "Write" && tool_input.file_path matches "\\.(md|txt)$" && !(tool_input.file_path matches "README\\.md|CLAUDE\\.md|AGENTS\\.md|CONTRIBUTING\\.md")node -e "const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path||'';if(/\.(md|txt)$/.test(p)&&!/(README|CLAUDE|AGENTS|CONTRIBUTING)\.md$/.test(p)){console.error('[Hook] BLOCKED: Unnecessary documentation file creation');console.error('[Hook] File: '+p);console.error('[Hook] Use README.md for documentation instead');process.exit(1)}console.log(d)})"tool == "Edit" || tool == "Write"node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/suggest-compact.js"*node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-end.js"*node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/evaluate-session.js"tool == "Bash"node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/gh pr create/.test(cmd)){const out=i.tool_output?.output||'';const m=out.match(/https:\/\/github.com\/[^/]+\/[^/]+\/pull\/\d+/);if(m){console.error('[Hook] PR created: '+m[0]);const repo=m[0].replace(/https:\/\/github.com\/([^/]+\/[^/]+)\/pull\/\d+/,'$1');const pr=m[0].replace(/.*\/pull\/(\d+)/,'$1');console.error('[Hook] To review: gh pr review '+pr+' --repo '+repo)}}console.log(d)})"tool == "Bash" && tool_input.command matches "(npm run build|pnpm build|yarn build)"node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{console.error('[Hook] Build completed - async analysis running in background');console.log(d)})"30mstool == "Edit" && tool_input.file_path matches "\\.(ts|tsx|js|jsx)$"node -e "const{execFileSync}=require('child_process');const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){try{execFileSync('npx',['prettier','--write',p],{stdio:['pipe','pipe','pipe']})}catch(e){}}console.log(d)})"tool == "Edit" && tool_input.file_path matches "\\.(ts|tsx)$"node -e "const{execSync}=require('child_process');const fs=require('fs');const path=require('path');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){let dir=path.dirname(p);while(dir!==path.dirname(dir)&&!fs.existsSync(path.join(dir,'tsconfig.json'))){dir=path.dirname(dir)}if(fs.existsSync(path.join(dir,'tsconfig.json'))){try{const r=execSync('npx tsc --noEmit --pretty false 2>&1',{cwd:dir,encoding:'utf8',stdio:['pipe','pipe','pipe']});const lines=r.split('\n').filter(l=>l.includes(p)).slice(0,10);if(lines.length)console.error(lines.join('\n'))}catch(e){const lines=(e.stdout||'').split('\n').filter(l=>l.includes(p)).slice(0,10);if(lines.length)console.error(lines.join('\n'))}}}console.log(d)})"tool == "Edit" && tool_input.file_path matches "\\.(ts|tsx|js|jsx)$"node -e "const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){const c=fs.readFileSync(p,'utf8');const lines=c.split('\n');const matches=[];lines.forEach((l,idx)=>{if(/console\.log/.test(l))matches.push((idx+1)+': '+l.trim())});if(matches.length){console.error('[Hook] WARNING: console.log found in '+p);matches.slice(0,5).forEach(m=>console.error(m));console.error('[Hook] Remove console.log before committing')}}console.log(d)})"*node "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-start.js"Share bugs, ideas, or general feedback.