diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0a1dcf6fe01c8c6e3dcf7d6b4b481ad0edd468ce..027e6533c0da10e394ff2574f3e064d05e43abc8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,6 +18,13 @@ jobs:
                 pipx install ruff
                 ruff check
 
+    typos:
+        name: Typos
+        runs-on: ubuntu-latest
+        steps:
+        -   uses: actions/checkout@v4
+        -   uses: crate-ci/typos@master
+
     pylint:
         name: Pylint
         runs-on: ubuntu-latest
diff --git a/pyproject.toml b/pyproject.toml
index 34ae84cab4e8238c4d9ed5aaf22f5b1bc854a436..bbdbb5e7df107c1356f220895318db079cc0a9bd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -42,3 +42,22 @@ known-local-folder = [
     "sumpy",
 ]
 lines-after-imports = 2
+
+[tool.typos.default]
+extend-ignore-re = [
+  "(?Rm)^.*(#|//)\\s*spellchecker:\\s*disable-line$"
+]
+
+[tool.typos.default.extend-words]
+# short for multi-indices
+mis = "mis"
+# short for n-dimensional
+nd = "nd"
+# short for Theorem
+thm = "thm"
+
+[tool.typos.files]
+extend-exclude = [
+  "contrib/*/*.ipynb",
+  "notes/*/*.eps",
+]
diff --git a/test/test_distributed.py b/test/test_distributed.py
index 2e3911bbde84e38d72aa499f37357a976fadfce0..60e94fff0aa22e9caf87a3a50d5af718b18f60ba 100644
--- a/test/test_distributed.py
+++ b/test/test_distributed.py
@@ -34,7 +34,7 @@ import pyopencl as cl
 
 
 def set_cache_dir(mpirank):
-    """Make each rank use a differnt cache location to avoid conflict."""
+    """Make each rank use a different cache location to avoid conflict."""
     import platformdirs
     cache_dir = platformdirs.user_cache_dir("sumpy", "sumpy")
 
@@ -122,11 +122,11 @@ def _test_against_single_rank(
             communicate_mpoles_via_allreduce=communicate_mpoles_via_allreduce)
 
     from boxtree.distributed import DistributedFMMRunner
-    distribued_fmm_info = DistributedFMMRunner(
+    distributed_fmm_info = DistributedFMMRunner(
         queue, global_tree_dev, traversal_builder, wrangler_factory, comm=comm)
 
     timing_data = {}
-    distributed_potential = distribued_fmm_info.drive_dfmm(
+    distributed_potential = distributed_fmm_info.drive_dfmm(
                 [sources_weights], timing_data=timing_data)
     assert timing_data