{"_id":"@coderifts/agent-hooks","_rev":"9-105a3ae118bbbdbc7eb64c5fb89f0c17","name":"@coderifts/agent-hooks","dist-tags":{"latest":"0.3.5"},"versions":{"0.2.0":{"name":"@coderifts/agent-hooks","version":"0.2.0","license":"MIT","_id":"@coderifts/agent-hooks@0.2.0","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"ef05b20b861c5b4eb55b4526c634405e36444f10","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.2.0.tgz","fileCount":11,"integrity":"sha512-Jb8EME8ci6Ths7GxUsYGGI4pompQKN7T58AlKm+fKC69CLz7WjPrQECXYOF1iOHnNLoPICWOfbSxrrlA/WeLLw==","signatures":[{"sig":"MEYCIQDzVY1NXoJVHNmLMjpDR2G1XJvrnjnHBeBydvMNYLcrfAIhALv9OpqsZ7neIvQiKnFgBiw3rZTkv+qsfF/sIM2JHAJw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30788},"main":"./index.js","type":"module","gitHead":"705717621d526164546a6ae2cfed1025e4779965","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.2.0_1789315552731_0.7029866187058753","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@coderifts/agent-hooks","version":"0.2.1","license":"MIT","_id":"@coderifts/agent-hooks@0.2.1","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"17b350d3b179a614ca0a8f1c868582cd61423de0","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.2.1.tgz","fileCount":12,"integrity":"sha512-Unxj8ZkxnlnPclPWBd6NQaPcfxZ5nNI9tYLe05NtavDMG43Npx9LiteGo7XkNgJQsgcpH/LBhqHIzt2mnWv1Zg==","signatures":[{"sig":"MEUCIFfBekseIa6glGo9Et88E8HdAfplmNaKp52Xop4Ngmn9AiEAzRdPKxUGzAGHNgBj8zLxBFV7MKTL/q0o8L4p1KUbgA4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBghmbEcy+1U7J1kAx8DDnjE/wlqVaAlxh4HxUmVOrxtAiEAsv9KMW4WWpgoFp+6iHKfl/SNZptpbveB007sL7kc/HU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37618},"main":"./index.js","type":"module","gitHead":"ed80e0378bfecfe39acdc6787dab2b8134d80f90","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.2.1_1790574212625_0.8250197708367495","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@coderifts/agent-hooks","version":"0.2.2","license":"MIT","_id":"@coderifts/agent-hooks@0.2.2","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"1b7063cd7479f5a6c7b80c08d77a12aa972262c3","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.2.2.tgz","fileCount":12,"integrity":"sha512-OezRQPZeAZE9oA0NK/Y1j99Iu7AoElQOtPp8hXyapw205oV5vZx68/sTAYO2R0/xYrx33xiffvxT7DXX4xsIzQ==","signatures":[{"sig":"MEUCIQDmkDD7g2fA5SvafM4FA+r7YiztkpN1N6lVthxP3RqBlgIgGDuFZhvlgM35GqgYFRMVTG7aT8LbsWagw1jqstldw+I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBTNuaPZ0RHCCNgkVtU+j7j0rH8xWg87gGQp1+XAoi8gAiBwUhpplj82dSwXZejcR7H/icJmznAglIrjamcE0ch6oA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39477},"main":"./index.js","type":"module","gitHead":"4e42b80d945d307d52b648b876192ff0398e4df6","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.2.2_1791028061425_0.21848457513455188","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@coderifts/agent-hooks","version":"0.3.0","license":"MIT","_id":"@coderifts/agent-hooks@0.3.0","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"2b958ba9ca3edb30228708bd5fb0ec7fbe8c4821","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.0.tgz","fileCount":13,"integrity":"sha512-nulv1kkWqdmTT3HwwJ+HJXrpftqt46ovsZwLittN0r5840ILTT3M0BuX8JDxPsdHbUSDoFtRKpmYJIQbqDb7hw==","signatures":[{"sig":"MEUCIQCZsHsm2hrCPMgvIFv2XEqxZ2jtHgbJI4e0MwVquPx9PQIgCWQTT87DFwFwqdmZs5KnxJeXq8FoSMOMPS/IURV/b1A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEHTBk3gPfImQWggh04OmXa6nkGfQH/pHAiRwZn8pT71AiASvE9Z+/4cD3IPWSlfChUQW39UGaIoLPOcwLKOaZqwAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":81503},"main":"./index.js","type":"module","gitHead":"73fa21a29e88768faae675e64d37ba75a284ebc3","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.3.0_1791057010242_0.7413070931353603","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@coderifts/agent-hooks","version":"0.3.1","license":"MIT","_id":"@coderifts/agent-hooks@0.3.1","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"770bbd58cebdb3c715df62f65e343a7dd3524ba5","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.1.tgz","fileCount":13,"integrity":"sha512-EBdOOzTST+9qK6UBaXzIaLRtar8i+ZeqWtIG4EJNVvs+2fOX0PF1yBrCa3lpEEQGb65zH3aqegyx37t5uDf7cA==","signatures":[{"sig":"MEQCIH6hcbOUdXIHL6Whp6S0nOptkp3oW2xlnm4zTfrQ7pZsAiBO1H7AiNI2DmcxvjGw8c7kykiudS1K+PqSqBYpECbIAw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIFCn6uRQIqixJhxnHCvBVZOs9JEGbetYd6Y1y5BYZAlsAiBy7QaV5XFIX8LimWPT0KUop5ovbk2uSaBDr5mA5nrjBQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82771},"main":"./index.js","type":"module","gitHead":"d2bff8849eb496091a405b6386e547a3ddda0352","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.3.1_1791131137614_0.708505426657275","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@coderifts/agent-hooks","version":"0.3.2","license":"MIT","_id":"@coderifts/agent-hooks@0.3.2","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"0af39d477c8caf2862e84e2bb4326d6e3deb3803","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.2.tgz","fileCount":13,"integrity":"sha512-EZC8T9tizHNTixLeNWNGKsY5JI1cpW9EvvGdtZ1HrDMe+HqzMKJqPiDfkR1Znl9SP4csfvgheL8a47dOauCXBg==","signatures":[{"sig":"MEQCIHwekq9TgCowEoL89l/9g4dSf+W+smd+pGtYn/GnLDBpAiBh+69fTTDQdoNcykk3wHrYQhwXiur/zji/GRSHp9XqLw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCd/L70twQvVIVAb5cvRQU0aBLqv74z9G9zqPqnTHlPcwIge4kP6bXYJCdAfbOQE+IGE+IPoUeVypaa3gI9lNigQtw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84111},"main":"./index.js","type":"module","gitHead":"688ff6b600381b55d25a62626b0b7f41cbd62631","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.3.2_1791316516224_0.7868149334533321","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@coderifts/agent-hooks","version":"0.3.3","license":"MIT","_id":"@coderifts/agent-hooks@0.3.3","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"8b9e352904dd45f47dfedc3e6e3a8f70118258ef","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.3.tgz","fileCount":13,"integrity":"sha512-D/fksMYMDr20cJhZduOnuOK644OMiWKneFEEZlR+/lH3fD2y1Az0u/xFgNAd3HpZZd6tbCuOZCLln/J7GD7lLA==","signatures":[{"sig":"MEUCIGGhruljyyyPYqNGt59H3eRlOY25kmbxOzM7UQK3TF3IAiEA/WLOdw5GHTlMgCMspDQW4TGB/O0C+mWC0TgNc4Fws2I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCbi3XYoKfyjUEA2nXWWkvtW4g7HLRkYH/A0bTgKuLcMAIhAPDEeKWNDISkcFrfr2xDLd+bO1iFL3LAyUqT6K9MiDYj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88423},"main":"./index.js","type":"module","gitHead":"8e187f4ae79e70ad6f24b8fe2e689caa3d452a37","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.3.3_1791447129164_0.20816444545814505","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"name":"@coderifts/agent-hooks","version":"0.3.4","license":"MIT","_id":"@coderifts/agent-hooks@0.3.4","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/agent-hooks#readme","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"88fe24ef2e9ef392d097ead4ce82b3df7b60e38e","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.4.tgz","fileCount":13,"integrity":"sha512-r3rHTa9LnrF+gI7W0YiJfvTPHDolzjWNtCO+5Vw6f6UtxhMa6EiNvdMlKa0+z7T+wXU/UyRmlJ4F3dH8wpb2Dw==","signatures":[{"sig":"MEYCIQDcUzq2Iqn9m0ACRW3p+eXL5H9xnbhhQ2/W3++kseeyMgIhAIJ1nlBxml2uW6KuGwg8xcoFLs+34lQnPlrgLNeBJM4x","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDHdGLX+Yurwg0uj/OhRwfhblMQLzt5qO2ZHZIIccnbiQIhANUWGWSkO8BOr8evr9Yf0amZqmrjdxrc3NyyCoZ2HrJb","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":92618},"main":"./index.js","type":"module","gitHead":"7259e4e98261948a6834d3f86bedf81d62a32339","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-hooks_0.3.4_1791556263748_0.03725083908822313","host":"s3://npm-registry-packages-npm-production"}},"0.3.5":{"_id":"@coderifts/agent-hooks@0.3.5","bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"dist":{"shasum":"b4d57d7612c50a9f30fdd8909eefbc9cd6bc0aa6","tarball":"https://registry.npmjs.org/@coderifts/agent-hooks/-/agent-hooks-0.3.5.tgz","fileCount":14,"integrity":"sha512-vgVAU1vE7HnHfAE7jkGvW276D3vMqWlzSJ1uGsbzrEtIwGZ7YJNwL1GnNbJ38wXZdgsy3ZmfbyOqnDVVVZx+Pg==","signatures":[{"sig":"MEUCIQD33fhPSdYMQztCdGTJiYbHTiw63/CgfywNrB6g4YkoigIgCctrVUkVXzGjVKrjlRm11QIstjgv9yPdRy9CXYmTCp4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEIjTCh7CAjMADficSiXxOhBjxvt2pip+3uGixchQUCUAiAzdG6A86BvPih/jzPtuk95MY8dEaFGPTim1wH4CWNuPA=="}],"unpackedSize":96615},"main":"./index.js","name":"@coderifts/agent-hooks","type":"module","gitHead":"69751b41f1899abc79dd31365be1ca3973f78626","license":"MIT","scripts":{"test":"node --test test/*.test.js"},"version":"0.3.5","_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"homepage":"https://github.com/coderifts/agent-hooks#readme","openclaw":{"build":{"openclawVersion":"2026.6.35"},"compat":{"pluginApi":">=2026.6.35"},"extensions":["./index.js"]},"repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"_npmVersion":"11.6.2","description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","directories":{},"maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"peerDependencies":{"openclaw":">=2026.6.35"},"peerDependenciesMeta":{"openclaw":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-hooks_0.3.5_1791563435503_0.4298625031134289"}}},"time":{"created":"2026-09-13T16:05:52.571Z","modified":"2026-10-09T16:30:35.771Z","0.2.0":"2026-09-13T16:05:52.860Z","0.2.1":"2026-09-28T05:43:32.708Z","0.2.2":"2026-10-03T11:47:41.525Z","0.3.0":"2026-10-03T19:50:10.323Z","0.3.1":"2026-10-04T16:25:37.706Z","0.3.2":"2026-10-06T19:55:16.323Z","0.3.3":"2026-10-08T08:12:09.251Z","0.3.4":"2026-10-09T14:31:03.831Z","0.3.5":"2026-10-09T16:30:35.587Z"},"bugs":{"url":"https://github.com/coderifts/agent-hooks/issues"},"license":"MIT","homepage":"https://github.com/coderifts/agent-hooks#readme","repository":{"url":"git+https://github.com/coderifts/agent-hooks.git","type":"git"},"description":"Ask CodeRifts before an agent writes a contract artifact (OpenClaw before_tool_call and Claude Code PreToolUse).","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"readme":"# CodeRifts agent hooks (`@coderifts/agent-hooks`)\n\nAsks CodeRifts before an agent writes a contract artifact — an OpenAPI, AsyncAPI, GraphQL,\nprotobuf or MCP manifest file. **Hosts today:** OpenClaw `before_tool_call` and Claude Code\n`PreToolUse`. **Not built:** the Docker MCP Gateway `before:exec` interceptor — that path\nwas measured (empty stdout = pass, CallToolResult JSON = block, HTTP 4xx empty = fail-open)\nand has no adapter in this package yet.\n\nThis is the host-adapter package. It is not `@coderifts/agent-guard` (the wrapWithGuard\nlibrary) and not `coderifts/contract-gate` (the GitHub Action). The npm name used to be\n`@coderifts/openclaw-plugin`; that name is wrong now that more than one host is wired.\n\nThe same `gate.js` drives every host. The gate makes no policy decisions of its own. It\nrecognises the file, sends the before/after to CodeRifts, and maps the answer back.\nEverything it cannot map, it puts to a human.\n\n## What it does\n\n| CodeRifts `execution_action` | OpenClaw | Claude Code PreToolUse |\n| --- | --- | --- |\n| `CONTINUE`, `CONTINUE_WITH_MONITORING` | pass through | exit 0, empty stdout (never `allow`) |\n| `REQUEST_APPROVAL` | `requireApproval` | JSON `permissionDecision: \"ask\"` |\n| `STOP` | `block`, with the reason and its limits | JSON `permissionDecision: \"deny\"` |\n| anything else, or no answer | `requireApproval` | **exit 2 + stderr** (host is fail-open) |\n\n## What it does not do\n\n- **It does not gate what it does not recognise.** A tool call writing `README.md` passes untouched.\n  The recognised set is a short, explicit list in `gate.js`; a gate that guesses at every file either\n  blocks documentation or waves through a schema.\n- **It does not turn a risk number into a verdict.** Without an API key CodeRifts answers in\n  `analyze` mode, which returns `authorization_effect: \"NONE\"` and `may_execute: false` — risk\n  information and no decision. The gate reports that and asks a human. It never reads a high score\n  as a block or a low one as a pass.\n- **It does not lock the file.** The bytes checked are the bytes in the tool params at the moment of\n  the call. Nothing here holds them between the answer and the write.\n\nEvery refusal says so in its own text, so an agent reading the transcript can see how far the answer\nreaches:\n\n```\nCodeRifts refused this contract change.\nReason: endpoint_removed — ENDPOINT_REMOVAL\nProves: the change set as this call would leave it was refused by CodeRifts under operation \"tool_call\".\nDoes not prove:\n  - that the bytes finally written are the bytes checked — nothing here locks the file between this answer and the write\n  - that the other tool calls in this run were checked — each call is judged alone\n  - that a contract artifact this gate does not recognise was seen at all\n  - that the call was refused when this hook is installed outside managed settings — since Claude Code 2.1.287 a user-installed mod runs before it, can answer the call so the hook never runs, and can approve a call the hook blocked; only a hook in managed settings is final, and a plugin hook runs after the mods even when managed settings force-enable the plugin\n  - that a call was refused when the hook ran out of time — the fail-closed path covers an error inside the hook, not Claude Code's hook timeout: a timed-out PreToolUse command hook does not block the call (true for this hook only when CODERIFTS_TIMEOUT_MS is at least the hook timeout)\n  - that the hook was running — disableAllHooks in any settings file (the project's .claude/settings.json included, which a shell command can rewrite unless the sandbox protects it), --safe-mode or --bare turns it off\n  - that a contract generated from source code was checked — a contract generated from source code (annotations, decorators, a build step) changes when the source changes; the hooks see the source edit, not the contract; the required check sees the generated contract\n```\n\n## Fail-closed\n\nIf CodeRifts is unreachable, times out, or answers something the gate cannot read, the result is\nnot a pass. Not knowing is not permission.\n\nThe gate's own budget defaults to 5000 ms.\n\nOn **OpenClaw**, that is well under the host's 15000 ms `before_tool_call` budget, so a slow\nanswer becomes a readable approval request, not an opaque host denial. The host is fail-closed.\n\nOn **Claude Code**, the host is **fail-open**: a timed-out command hook, exit 1, invalid JSON,\nor a missing script lets the tool run. The adapter therefore maps those failures to **exit 2**.\nThe hook entry sets `\"timeout\": 8` (**seconds** — Claude Code's unit, not milliseconds) so the\ngate's 5000 ms abort can finish first. If `node` itself hangs past 8 s, Claude Code still\nlets the write through. That host behaviour cannot be fixed in this package.\n\n## Shell writes (Claude Code)\n\nThe Claude Code matcher is `Write|Edit|MultiEdit|Bash`. A shell command cannot be gated — the\nhook never sees the bytes it would leave — so the hook reads what the command **writes**, with the\ndecision function `coderifts claude-hook` and the CodeRifts mod use too (`contract-write.mjs`, a\ncopy of `@coderifts/contract-path`'s):\n\n- **A write to a named contract file is denied** (a redirect into it, `tee`, `sed -i`/`perl -i`,\n  the destination of `cp`/`install`/`ln`/`rsync`, `mv`/`rm`, `git checkout|restore -- <file>`,\n  `--out <file>`, `open(<file>, \"w\")` in inline Python or Node, `curl -o`), with a pointer to the\n  Write or Edit tool, where the gate does see the change. Nothing is sent to CodeRifts for a Bash call.\n- **A write that can reach a contract file without naming it asks**: `find <dir> -exec sed -i …`\n  or `-delete`, `xargs` into a writer, a glob, `rm -rf <dir>`, `git stash pop`, `git reset --hard`,\n  `git checkout -- .`, inline code that walks a directory, a pipe into `sh`, a target the command\n  builds from a variable it does not set. It asks only when a contract file is under that\n  directory; `find . -name '*.pyc' -delete` and `rm -rf build` pass.\n- **A read passes**, even of a contract file: `cat openapi.yaml > /tmp/copy`, `cp openapi.yaml /tmp/`,\n  `git diff`, `grep`, `oasdiff`.\n\nMeasured on 2026-10-03 on two corpora: the 22 benign forms of the Skillkeel tamper corpus pass; 12 of\nits 83 tamper cases ask, each a write that reaches the working tree without naming a file (`rm -rf .`,\n`git reset --hard`, `git clean -fdx`, `git checkout -- .`, `xargs rm`, a pipe into `sh`); of our 16\ncontract-file-write cases, the 11 that change a contract are stopped and the 5 benign ones go through.\n\nAn ask does not weaken a deny: on Claude Code 2.1.288 a settings `deny` rule held over this hook's\n`ask` and over an `allow` (measured in `bypassPermissions` mode). The earlier report that a hook ask\noverrode a deny rule (anthropics/claude-code #39344) did not reproduce.\n\nIt reads the command text; it does not parse shell or run it. A command shape it does not recognise\npasses — a script that writes a contract file itself (`node scripts/generate.js`), a variable it\ncannot resolve to a name — and every shell refusal says so:\n\nDoes not prove:\n  - that a contract file written by a shell command this hook did not recognise was seen at all\n\nThe sandbox closes what the text cannot: with `sandbox.filesystem.denyWrite` listing the contract\npaths, every sandboxed command and its child processes are refused the write (measured on macOS:\n`python -c`, `find -exec sed -i`, `xargs cp`, also in `bypassPermissions` mode; on Linux a wildcard\nentry is skipped, so list concrete paths). The Write and Edit tools stay with this hook.\n\n## Edit and MultiEdit\n\n`new_string` is a fragment, not the file. The gate reads the file on disk and sends it with the\nedit applied (MultiEdit: every edit, in order). An edit whose `old_string` is not in the file is\nnot guessed: exit 2.\n\n## Configuration\n\n```json\n{\n  \"plugins\": {\n    \"entries\": {\n      \"coderifts-contract-gate\": {\n        \"config\": {\n          \"apiKey\": \"...\",\n          \"endpoint\": \"https://app.coderifts.com/mcp\",\n          \"timeoutMs\": 5000,\n          \"operation\": \"tool_call\"\n        }\n      }\n    }\n  }\n}\n```\n\n`apiKey` is optional in the schema and load-bearing in practice: **without it there is no decision.**\n`preflight_mode=authorize` requires a verified issuer, so an unkeyed gate runs in `analyze` mode and\nevery gated call ends at a human. That is safe and it is noisy; the key is what makes it useful.\n\nThere is no setting that makes an unanswered call pass. That absence is the design.\n\n## Hook placement\n\nRegistered on `before_tool_call` at `priority: 100`. OpenClaw runs handlers in descending priority\nand keeps only the **first** `requireApproval`, so a gate that runs late can have its question\ndropped by an earlier plugin. A `block` is sticky and survives regardless of order.\n\n## Install — OpenClaw\n\n```bash\nopenclaw plugins install @coderifts/agent-hooks\n```\n\n(OpenClaw still records the plugin under the runtime id `coderifts-contract-gate` — that is\nthe OpenClaw config key, not the GitHub Action.)\n\n## Install — Claude Code\n\nCopy `claude-code/settings.snippet.json` into `.claude/settings.json` (or merge the\n`hooks` key), after `npm install @coderifts/agent-hooks`. Optional env:\n`CODERIFTS_API_KEY`, `CODERIFTS_ENDPOINT`, `CODERIFTS_TIMEOUT_MS` (milliseconds, gate\nbudget; default 5000).\n\nPlugin shape (for the existing `coderifts` marketplace): `.claude-plugin/plugin.json` +\n`hooks/hooks.json`. Add `claude-code/marketplace-entry.json` to\n`coderifts/api-governance` `.claude-plugin/marketplace.json` `plugins` array — that\ncatalog today lists only `api-governance`. Then:\n\n```bash\nclaude plugin marketplace update coderifts\nclaude plugin install agent-hooks@coderifts\n```\n\nDo not use `permissionDecision: allow` for CONTINUE. Empty exit 0 leaves the normal\npermission prompt in place.\n\n## Test\n\n```bash\nnpm test\n```\n\n`npm test` includes a pack-then-install case. In-repo imports cannot see a\n`files` allowlist that dropped a relative module — that is how 0.1.0 shipped\nwithout `gate.js`. The pack test also requires `claude-code/hook.mjs`. Do not\nskip it.\n","readmeFilename":"README.md"}