diff --git a/.husky/commit-msg b/.husky/commit-msg
index cdb7c8da869163f91bf0872e5bc4c35ed00bc53d..ae61f5b1bf9a2cb5eb40b7ebdf0a941a9df4f111 100755
--- a/.husky/commit-msg
+++ b/.husky/commit-msg
@@ -1,4 +1,4 @@
 #!/bin/sh
 . "$(dirname "$0")/_/husky.sh"
 
-npx --no-install commitlint --verbose --edit "$1"
+pnpm exec commitlint --verbose --edit "$1"
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 39c89b162e83a15a283303cd18f898ac0cf096f1..bc1c3599e831cfe2708946e74416db1d5b1f1b29 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -7,5 +7,5 @@ INTERACTIVE="--no-interaction"
 
 vendor/bin/captainhook $INTERACTIVE --configuration=captainhook.json --bootstrap=vendor/autoload.php hook:pre-commit "$@" <&0
 
-npm run typecheck
-npx lint-staged
+pnpm run typecheck
+pnpm exec lint-staged
diff --git a/.releaserc.json b/.releaserc.json
index a9deb7730d7ad9c3f7f6d16968089d555ecd75ce..af98b785dea6fe0662c96944c00f1ce74587a0b7 100644
--- a/.releaserc.json
+++ b/.releaserc.json
@@ -17,7 +17,7 @@
     [
       "@semantic-release/exec",
       {
-        "prepareCmd": "./scripts/bundle.sh ${nextRelease.version} && ./scripts/package.sh ${nextRelease.version} && npx prettier --write CHANGELOG.md"
+        "prepareCmd": "./scripts/bundle.sh ${nextRelease.version} && ./scripts/package.sh ${nextRelease.version} && pnpm exec prettier --write CHANGELOG.md"
       }
     ],
     "@semantic-release/npm",
diff --git a/docker/ci/Dockerfile b/docker/ci/Dockerfile
index 58fe8f126f6ee9facaba6ca9b415de8d3daca513..f24e368926aef93d088f06874859b410f2e285ab 100644
--- a/docker/ci/Dockerfile
+++ b/docker/ci/Dockerfile
@@ -19,6 +19,7 @@ RUN \
         wget \
         jq \
         zip \
+        openssh-client \
         rsync \
         icu-libs \
         mysql \
diff --git a/docs/.gitlab-ci.yml b/docs/.gitlab-ci.yml
index f9c992b7704e4829ba489c34d8153327abe79ef5..1569b949877b139170d10ef27cce30487b3ffe22 100644
--- a/docs/.gitlab-ci.yml
+++ b/docs/.gitlab-ci.yml
@@ -9,7 +9,7 @@ stages:
     - cd docs
     - chmod +x ./scripts/i18n-filter.sh
     - ./scripts/i18n-filter.sh src
-    - npm ci
+    - pnpm install
 
 cache:
   paths:
@@ -20,7 +20,7 @@ build:
   extends: .documentation-setup
   stage: build
   script:
-    - npm run build
+    - pnpm run build
   except:
     - main
     - beta
@@ -33,7 +33,7 @@ build-production:
     name: production
     url: https://docs.castopod.org/
   script:
-    - npm run build
+    - pnpm run build
   artifacts:
     paths:
       - docs/.vitepress/dist
@@ -56,10 +56,6 @@ deploy:
     SSH_PORT: 3242
     SOURCE_FOLDER: "docs/.vitepress/dist/"
   before_script:
-    # install rsync for file transfers
-    - apt-get update && apt-get install rsync -y
-    # ssh config
-    - "which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )"
     # Run ssh-agent (inside the build environment)
     - eval $(ssh-agent -s)
     # Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
diff --git a/scripts/lint-commit-msg.sh b/scripts/lint-commit-msg.sh
index 22b81624bfe0b38436746eba454a168a325052fa..173d5821f9df24f86bb8b9d825dd80a019893204 100755
--- a/scripts/lint-commit-msg.sh
+++ b/scripts/lint-commit-msg.sh
@@ -6,14 +6,14 @@ set -e
 if [ "${CI_COMMIT_BEFORE_SHA}" = "0000000000000000000000000000000000000000" ];
 then
     echo "commitlint from HEAD^"
-    pnpx commitlint --from=HEAD^
+    pnpm exec commitlint --from=HEAD^
 else
     echo "commitlint from ${CI_COMMIT_BEFORE_SHA}"
     br=`git branch -r --contains ${CI_COMMIT_BEFORE_SHA}`
     if [ ! -n $br ];
     then 
-        pnpx commitlint --from=HEAD^
+        pnpm exec commitlint --from=HEAD^
     else
-        pnpx commitlint --from="${CI_COMMIT_BEFORE_SHA}"
+        pnpm exec commitlint --from="${CI_COMMIT_BEFORE_SHA}"
     fi
 fi