diff --git a/.husky/.gitattributes b/.husky/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.husky/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000..70bd3dd
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1 @@
+npx --no-install commitlint --edit "$1"
diff --git a/package-lock.json b/package-lock.json
index 890fea2..afc4861 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
         "@commitlint/config-conventional": "^19.7.1",
         "eslint": "^8.16.0",
         "eslint-config-scratch": "^7.0.0",
+        "husky": "^9.1.7",
         "scratch-semantic-release-config": "1.0.8",
         "tap": "^16.2.0"
       }
@@ -4410,6 +4411,21 @@
         "node": ">=10.17.0"
       }
     },
+    "node_modules/husky": {
+      "version": "9.1.7",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
+      "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
+      "dev": true,
+      "bin": {
+        "husky": "bin.js"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/typicode"
+      }
+    },
     "node_modules/ignore": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
@@ -20907,6 +20923,12 @@
       "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
       "dev": true
     },
+    "husky": {
+      "version": "9.1.7",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
+      "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
+      "dev": true
+    },
     "ignore": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
diff --git a/package.json b/package.json
index e797563..fdba42e 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
     "test": "test"
   },
   "scripts": {
+    "prepare": "husky || true",
     "test": "npm run test:lint && npm run test:unit",
     "test:lint": "eslint .",
     "test:unit": "tap --reporter nyan test/unit/*.js --statements=97 --branches=97"
@@ -24,6 +25,7 @@
     "@commitlint/config-conventional": "^19.7.1",
     "eslint": "^8.16.0",
     "eslint-config-scratch": "^7.0.0",
+    "husky": "^9.1.7",
     "scratch-semantic-release-config": "1.0.8",
     "tap": "^16.2.0"
   }