diff --git a/bin/shpkg_ci_mux b/bin/shpkg_ci_mux
new file mode 100755
index 0000000..44424a2
--- /dev/null
+++ b/bin/shpkg_ci_mux
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+set -e
+
+# shpkg
+
+: ${SHPKG_DIR:=~/shpkg}
+
+. "${SHPKG_DIR}/etc/shpkg/profile"
+
+. "${SHPKG_DIR}/share/shpkg/shpkg.subr"
+
+verbose 2 shpkg_config
+
+verbose 2 shpkg_lock shpkg_ci_mux.lock
+
+# Configuration
+
+: ${SHPKG_CI_DIR:=${SHPKG_DIR}/ci}
+
+shpkg_ci_remote () {
+ verbose 1 ssh "$1" sh -c "\"shpkg/bin/shpkg_ci '$2'\""
+ if [ "x$2" != "x--upgrade" ]; then
+ verbose 1 rsync -a "$1":shpkg/ci/. "${SHPKG_CI_DIR}/"
+ fi
+}
+
+main () {
+ SHPKG_REPO="$1"
+ shift
+ for SHPKG_CI_MUX_HOST; do
+ shpkg_ci_remote "${SHPKG_CI_MUX_HOST}" "${SHPKG_REPO}" &
+ done
+ for SHPKG_CI_MUX_HOST; do
+ wait
+ done
+ if [ "x${SHPKG_REPO}" == "x--upgrade" ]; then
+ exit
+ fi
+ ( cd "${SHPKG_CI_DIR}/status" &&
+ for S in $(ls */*/*.status | cut -d / -f 3 | sort -u); do
+ {
+ if grep -q running */*/"$S"; then
+ echo running
+ elif grep -q ko */*/"$S"; then
+ echo ko
+ else
+ echo ok
+ fi
+ } > "${SHPKG_CI_DIR}/status/$S"
+ done; )
+}
+
+shpkg_log shpkg_ci_mux main "$@"