Installer source / review before running
Read every line.
Before it runs.
The exact shell script served at
/install.sh. Review the source, inspect the checksums, and know what you run.A clear installation path.
- Displayed source
- Exact script bundled into this build and served at /install.sh.
- Published release
- WaitDojo v0.2.6 for macOS, Linux, and WSL2.
- Archive integrity
- SHA-256 detects a corrupt or mismatched downloaded archive.
- Trust boundary
- Detached Ed25519 signatures and signed provenance cover every archive. A fresh install still needs an out-of-band trusted public key for independent publisher authentication.
02 / Before your first rep
Public installer, invited access.
The installer source and release downloads are public. Running the installer does not grant beta access or create an entitlement.
Invited access starts when a private invitation is claimed with GitHub and the site records that account entitlement. Beta-gated builds check the same GitHub account at launch.
The published v0.2.6 beta-gated builds require a claimed invitation and check access at launch. An uninvited account cannot start installed drills. Progress backup is optional.
Join the invited-beta waitlistPublished installer source.
The source below is inert text. Nothing runs here. Use the explicitly labeled raw file only if you want to download it.
waitdojo-install.sh — bash#!/bin/shset -eu# Installer output and checksum/archive tools must behave the same on GNU and# BSD userlands, even when the calling terminal exports a locale unavailable on# the target host (for example C.UTF-8 on macOS).LC_ALL=CLANG=Cexport LC_ALL LANGPRODUCT="waitdojo"BASE_URL="${WAITDOJO_BASE_URL:-https://waitdojo.dev/releases}"VERSION="${WAITDOJO_VERSION:-latest}"DEFAULT_INSTALL_DIR="$HOME/.local/bin"INSTALL_DIR="${WAITDOJO_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"DRY_RUN="${WAITDOJO_DRY_RUN:-0}"NO_MODIFY_PATH="${WAITDOJO_NO_MODIFY_PATH:-0}"AGENT="${WAITDOJO_AGENT:-}"PATH_PROFILE_CONFIGURED=0SETUP_SUPPORTED=0usage() {cat <<'EOF'Usage: install.sh [--dry-run] [--no-modify-path] [--agent codex|claude|none]Environment:WAITDOJO_INSTALL_DIR install directory, defaults to ~/.local/binWAITDOJO_VERSION release version, defaults to latestWAITDOJO_BASE_URL release base URL, defaults to the live WaitDojo siteWAITDOJO_DRY_RUN set to 1 to print actions without changing filesWAITDOJO_NO_MODIFY_PATHset to 1 to leave shell profiles unchangedWAITDOJO_AGENT optionally configure codex or claude hooks after installEOF}while [ "$#" -gt 0 ]; docase "$1" in--dry-run)DRY_RUN=1;;--no-modify-path)NO_MODIFY_PATH=1;;--agent)shiftif [ "$#" -eq 0 ]; thenecho "--agent requires codex, claude, or none" >&2exit 2fiAGENT="$1";;-h|--help)usageexit 0;;*)echo "unknown argument: $1" >&2usage >&2exit 2;;esacshiftdonecase "$AGENT" in""|none) AGENT="" ;;codex|claude) ;;*)echo "WAITDOJO_AGENT/--agent must be codex, claude, or none" >&2exit 2;;esaccase "$NO_MODIFY_PATH" in0|1) ;;*)echo "WAITDOJO_NO_MODIFY_PATH must be 0 or 1" >&2exit 2;;esaccase "$INSTALL_DIR" in/*) ;;*) INSTALL_DIR="$PWD/$INSTALL_DIR" ;;esacdetect_os() {os="${WAITDOJO_TEST_UNAME_S:-$(uname -s 2>/dev/null || true)}"case "$os" inDarwin) echo "macos" ;;Linux) echo "linux" ;;MINGW*|MSYS*|CYGWIN*)echo "native Windows is not supported; install and run WaitDojo inside WSL2" >&2exit 1;;*)echo "unsupported OS: $os" >&2exit 1;;esac}detect_arch() {arch="${WAITDOJO_TEST_UNAME_M:-$(uname -m 2>/dev/null || true)}"case "$arch" inx86_64|amd64) echo "x64" ;;arm64|aarch64) echo "arm64" ;;*)echo "unsupported architecture: $arch" >&2exit 1;;esac}need_cmd() {if ! command -v "$1" >/dev/null 2>&1; thenecho "missing required command: $1" >&2exit 1fi}is_wsl2() {if [ "${WAITDOJO_TEST_WSL:-}" = "1" ]; thenreturn 0fiif [ -n "${WSL_INTEROP:-}" ] || [ -n "${WSL_DISTRO_NAME:-}" ]; thenreturn 0fiif [ -r /proc/sys/kernel/osrelease ] && grep -qi "microsoft\\|wsl" /proc/sys/kernel/osrelease; thenreturn 0fireturn 1}append_posix_path_block() {profile="$1"marker="# >>> waitdojo PATH >>>"if grep -F "$marker" "$profile" >/dev/null 2>&1; thenecho "PATH already configured in $profile"PATH_PROFILE_CONFIGURED=1return 0fiif {if [ -s "$profile" ]; thenprintf '\n'fiprintf '%s\n' \"$marker" \'# Added by the WaitDojo installer. Remove this block to opt out.' \'case "$PATH" in' \' "$HOME/.local/bin"|"$HOME/.local/bin":*) ;;' \' *) export PATH="$HOME/.local/bin:$PATH" ;;' \'esac' \'# <<< waitdojo PATH <<<'} >>"$profile"thenecho "configured PATH in $profile"PATH_PROFILE_CONFIGURED=1elseecho "warning: could not update PATH in $profile" >&2fi}append_fish_path_block() {profile="$1"marker="# >>> waitdojo PATH >>>"profile_dir="${profile%/*}"if ! mkdir -p "$profile_dir"; thenecho "warning: could not create $profile_dir for PATH setup" >&2return 0fiif grep -F "$marker" "$profile" >/dev/null 2>&1; thenecho "PATH already configured in $profile"PATH_PROFILE_CONFIGURED=1return 0fiif {if [ -s "$profile" ]; thenprintf '\n'fiprintf '%s\n' \"$marker" \'# Added by the WaitDojo installer. Remove this block to opt out.' \'if not contains -- "$HOME/.local/bin" "$PATH[1]"' \' set -gx PATH "$HOME/.local/bin" $PATH' \'end' \'# <<< waitdojo PATH <<<'} >>"$profile"thenecho "configured PATH in $profile"PATH_PROFILE_CONFIGURED=1elseecho "warning: could not update PATH in $profile" >&2fi}configure_shell_path() {if [ "$NO_MODIFY_PATH" = "1" ]; thenecho "PATH setup skipped (--no-modify-path)"return 0fiif [ "$INSTALL_DIR" != "$DEFAULT_INSTALL_DIR" ]; thenecho "PATH setup skipped for custom install directory $INSTALL_DIR"return 0fishell_path="${SHELL:-}"shell_name="${shell_path##*/}"case "$shell_name" inbash)append_posix_path_block "$HOME/.bashrc"if [ -f "$HOME/.bash_profile" ]; thenappend_posix_path_block "$HOME/.bash_profile"elif [ -f "$HOME/.bash_login" ]; thenappend_posix_path_block "$HOME/.bash_login"elseappend_posix_path_block "$HOME/.profile"fi;;zsh)append_posix_path_block "${ZDOTDIR:-$HOME}/.zshrc";;fish)append_fish_path_block "${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d/waitdojo.fish";;""|sh|dash|ash|ksh)append_posix_path_block "$HOME/.profile";;*)echo "warning: shell $shell_name is not supported for automatic PATH setup" >&2;;esac}current_waitdojo_path() {command -v "$PRODUCT" 2>/dev/null || true}warn_if_shadowed() {installed="$INSTALL_DIR/$PRODUCT"resolved="$(current_waitdojo_path)"if [ -z "$resolved" ] || [ "$resolved" = "$installed" ]; thenreturn 0fiecho "warning: another waitdojo currently wins on PATH: $resolved" >&2if [ -x "$resolved" ]; thenshadow_version="$("$resolved" --version 2>/dev/null || true)"if [ -n "$shadow_version" ]; thenecho " existing: $shadow_version" >&2fifiecho " installed: $installed" >&2echo " prepend the installed directory now or open a new terminal after PATH setup" >&2}print_next_steps() {if [ "$RUNTIME" = "wsl2" ]; thenecho " workspace: keep source checkouts under WSL, for example ~/waitdojo, not /mnt/c/..."firesolved="$(current_waitdojo_path)"if [ "$resolved" != "$INSTALL_DIR/$PRODUCT" ]; thenif [ "$INSTALL_DIR" = "$DEFAULT_INSTALL_DIR" ]; thenshell_install_dir='$HOME/.local/bin'elseshell_install_dir="$INSTALL_DIR"fiecho " current shell: export PATH=\"${shell_install_dir}:\$PATH\""echo " hash -r 2>/dev/null || true"if [ "$PATH_PROFILE_CONFIGURED" = "1" ]; thenecho " future shells: PATH is configured; open a new terminal"elif [ "$NO_MODIFY_PATH" = "1" ]; thenecho " future shells: add the install directory to PATH yourself"elif [ "$DRY_RUN" = "1" ] && [ "$INSTALL_DIR" = "$DEFAULT_INSTALL_DIR" ]; thenecho " future shells: the installer will configure PATH automatically"elseecho " future shells: add export PATH=\"${shell_install_dir}:\$PATH\" to your shell profile"fifiif [ -n "$AGENT" ]; thenif [ "$DRY_RUN" = "1" ]; thenecho " setup: would configure $AGENT using the downloaded version's setup or init command"elif [ "$SETUP_SUPPORTED" = "1" ]; thenecho " setup: $PRODUCT setup --agent $AGENT completed"elseecho " setup: passive $AGENT hooks configured via $PRODUCT init $AGENT"fiecho " review: open $AGENT and run /hooks"echo " launch: $INSTALL_DIR/$PRODUCT"elseecho " start: $PRODUCT"echo " detects your configured agent and opens the project sidecar"if [ "$SETUP_SUPPORTED" = "1" ]; thenecho " setup: $PRODUCT setup --agent codex # or: --agent claude"elseecho " setup: $PRODUCT init codex # or: $PRODUCT init claude"fiecho " launch: $PRODUCT codex # or: $PRODUCT claude"fiecho " local: $PRODUCT pane"echo " toggle: Ctrl+G or click [↑ open WaitDojo] / [↓ collapse]"echo " advanced: tmux prefix, then C-g, then an action key"echo " check: $PRODUCT doctor --product --agent ${AGENT:-codex}"echo " tools:"for cmd in cargo tmux codex claude; doif command -v "$cmd" >/dev/null 2>&1; thenecho " $cmd: ok"elseecho " $cmd: missing"fidone}OS="$(detect_os)"ARCH="$(detect_arch)"RUNTIME="$OS"if [ "$OS" = "linux" ] && is_wsl2; thenRUNTIME="wsl2"fiASSET="${PRODUCT}-${OS}-${ARCH}.tar.gz"URL="${BASE_URL}/${VERSION}/${ASSET}"case "$VERSION" in""|*[!0-9A-Za-z.+-]*)echo "invalid requested WaitDojo version: $VERSION" >&2exit 2;;esacecho "WaitDojo installer"echo " runtime: ${RUNTIME}"echo " platform: ${OS}-${ARCH}"echo " asset: ${ASSET}"echo " install: ${INSTALL_DIR}/${PRODUCT}"echo " source: ${URL}"if [ "$DRY_RUN" = "1" ]; thenecho "dry run: no files changed"echo "next steps:"print_next_stepsexit 0fineed_cmd curlneed_cmd tarneed_cmd installneed_cmd mktempneed_cmd awkneed_cmd grepif command -v sha256sum >/dev/null 2>&1; thenCHECKSUM_COMMAND="sha256sum"elif command -v shasum >/dev/null 2>&1; thenCHECKSUM_COMMAND="shasum"elseecho "missing required command: sha256sum or shasum" >&2exit 1fimkdir -p "$INSTALL_DIR"tmp_dir="$(mktemp -d)"trap 'rm -rf "$tmp_dir"' EXIT INT TERMread_latest_version() {version_url="${BASE_URL}/latest/VERSION"curl -fsSL "$version_url" -o "$tmp_dir/VERSION"published_version="$(awk 'NF {lines += 1value = $0sub(/\r$/, "", value)}END {if (lines != 1 || value == "" || value ~ /[[:space:]]/) exit 1print value}' "$tmp_dir/VERSION")" || {echo "invalid published VERSION from $version_url" >&2exit 1}case "$published_version" in""|*[!0-9A-Za-z.+-]*)echo "invalid published WaitDojo version: $published_version" >&2exit 1;;esac}if [ "$VERSION" = "latest" ]; thenread_latest_versionexpected_version="$published_version"curl -fsSL "$URL" -o "$tmp_dir/$ASSET"elseexpected_version="$VERSION"# Prefer the immutable version directory. Older sites published only latest;# use that location only after proving it names exactly the requested version.# The archive checksum and executable version are verified again below, so a# concurrent latest promotion cannot silently install a different release.if ! curl -fsSL "$URL" -o "$tmp_dir/$ASSET"; thenread_latest_versionif [ "$published_version" != "$expected_version" ]; thenecho "requested WaitDojo $expected_version is unavailable; latest is $published_version; no binary was installed" >&2exit 1fiURL="${BASE_URL}/latest/${ASSET}"echo " source: $URL (verified latest is exactly $expected_version)"curl -fsSL "$URL" -o "$tmp_dir/$ASSET"fificase "$expected_version" in""|*[!0-9A-Za-z.+-]*)echo "invalid requested or published WaitDojo version: $expected_version" >&2exit 1;;esacchecksum_url="${URL}.sha256"curl -fsSL "$checksum_url" -o "$tmp_dir/$ASSET.sha256"expected_checksum="$(awk -v asset="$ASSET" 'NF {lines += 1name = $2sub(/^\*/, "", name)sub(/\r$/, "", name)hash = tolower($1)sub(/\r$/, "", hash)if (lines != 1 || NF != 2 || name != asset || length(hash) != 64 || hash !~ /^[0-9a-f]+$/) {invalid = 1}expected = hash}END {if (lines != 1 || invalid) exit 1print expected}' "$tmp_dir/$ASSET.sha256")" || {echo "invalid checksum file from $checksum_url" >&2exit 1}if [ "$CHECKSUM_COMMAND" = "sha256sum" ]; thenactual_checksum="$(sha256sum "$tmp_dir/$ASSET")"elseactual_checksum="$(shasum -a 256 "$tmp_dir/$ASSET")"fiactual_checksum="${actual_checksum%% *}"if [ "$actual_checksum" != "$expected_checksum" ]; thenecho "checksum verification failed for $ASSET" >&2exit 1fiecho "$ASSET: checksum verified"tar -xzf "$tmp_dir/$ASSET" -C "$tmp_dir"if [ ! -f "$tmp_dir/$PRODUCT" ] || [ ! -x "$tmp_dir/$PRODUCT" ]; thenecho "archive did not contain $PRODUCT binary" >&2exit 1fiversion_output="$("$tmp_dir/$PRODUCT" --version)"printf '%s\n' "$version_output" >"$tmp_dir/version.txt"if [ "$version_output" != "$PRODUCT $expected_version" ]; thenecho "downloaded WaitDojo version mismatch: expected $PRODUCT $expected_version, got $version_output" >&2exit 1fi"$tmp_dir/$PRODUCT" --help >"$tmp_dir/help.txt"if grep -Eq '^[[:space:]]*setup([[:space:]]|$)' "$tmp_dir/help.txt"; thenSETUP_SUPPORTED=1fiif ! grep -Eq '(^|[[:space:]])codex([[:space:]]|$)' "$tmp_dir/help.txt" || \! grep -Eq '(^|[[:space:]])claude([[:space:]]|$)' "$tmp_dir/help.txt"; thenecho "downloaded WaitDojo build is missing Codex or Claude Code support" >&2exit 1fivalidation_home="$tmp_dir/validation-home"mkdir -p "$validation_home"HOME="$validation_home" \CODEX_HOME="$validation_home/.codex" \WAITDOJO_DATA_DIR="$validation_home/.codex/waitdojo" \"$tmp_dir/$PRODUCT" init codex --dry-run --allow-dev-path >/dev/nullHOME="$validation_home" \CLAUDE_CONFIG_DIR="$validation_home/.claude" \WAITDOJO_DATA_DIR="$validation_home/.codex/waitdojo" \"$tmp_dir/$PRODUCT" init claude --dry-run --allow-dev-path >/dev/nullecho "$PRODUCT: Codex and Claude Code support verified"install -m 0755 "$tmp_dir/$PRODUCT" "$INSTALL_DIR/$PRODUCT""$INSTALL_DIR/$PRODUCT" --version >/dev/null# Bake the install-time campaign bucket (WAITDOJO_CAMPAIGN_BUCKET, if set)# into the installation identity now; without this, installs that skip# --agent lose attribution because the env var is gone by first launch."$INSTALL_DIR/$PRODUCT" install-stamp >/dev/null 2>&1 || trueecho "installed $PRODUCT to $INSTALL_DIR/$PRODUCT"configure_shell_pathwarn_if_shadowedif [ -n "$AGENT" ]; thenif [ "$SETUP_SUPPORTED" = "1" ]; thenecho "configuring $AGENT via waitdojo setup"if "$INSTALL_DIR/$PRODUCT" setup --agent "$AGENT"; then:elsesetup_status=$?echo "WaitDojo was installed, but $AGENT setup did not complete (exit $setup_status)." >&2echo "Resolve the reported checks, then rerun: \"$INSTALL_DIR/$PRODUCT\" setup --agent $AGENT" >&2echo "Launch WaitDojo to finish sign-in and access checks: \"$INSTALL_DIR/$PRODUCT\" pane" >&2exit "$setup_status"fielseecho "configuring passive $AGENT hooks via waitdojo init $AGENT"if "$INSTALL_DIR/$PRODUCT" init "$AGENT"; then:elsesetup_status=$?echo "WaitDojo was installed, but $AGENT hook setup failed (exit $setup_status)." >&2echo "Resolve the error, then rerun: \"$INSTALL_DIR/$PRODUCT\" init $AGENT" >&2echo "Launch WaitDojo to finish sign-in and access checks: \"$INSTALL_DIR/$PRODUCT\" pane" >&2exit "$setup_status"fififiecho "next steps:"print_next_steps