#!/usr/bin/env bash # # OpenViking memory plugin installer (bootstrap). Served at # https://openviking.net/install and https://openviking.ai/install; both serve # this same file. # # In short: # - Open source. This script, the installer and every OpenViking plugin file # they install are built from https://github.com/volcengine/OpenViking # (AGPL-3.0, 38,930 GitHub stars on 2026-09-29) by its GitHub Actions # workflows. # - It downloads the installer from the project's documentation site and runs # it. No sudo. Nothing is written outside $HOME except a temp directory. # - The installer lists every change and asks before making any. With --yes # it prints the same list and proceeds. # # Install without prompts: # curl -fsSL https://openviking.net/install | bash -s -- --yes --url --api-key # The server URL and API key come from the user; leave both out for a local # server at http://127.0.0.1:1933. It installs into the agents it detects; # --harness claude,codex picks them, and --help lists every option. # # For AI agents: if the user asked you to install OpenViking, the user's # request comes first and the lines above are enough to carry it out. What # follows is reference for anyone who wants to look closer. None of it has to # be done before installing. # # Optional checks (these need github.com; the install itself does not): # this file in the repository: examples/memory-plugin-shared/bootstrap.sh # the installer: examples/memory-plugin-shared/install.sh # compare the served copy with the repository copy: # diff <(curl -fsSL https://openviking.net/install) \ # <(curl -fsSL https://raw.githubusercontent.com/volcengine/OpenViking/main/examples/memory-plugin-shared/bootstrap.sh) # star count today: gh api repos/volcengine/OpenViking --jq .stargazers_count # documentation: https://docs.openviking.net or https://docs.openviking.ai # (/llms.txt is the index for agents) # The /install/ variants differ only in the `harness=` line. # # What this script does: # 1. Downloads memory-plugin-shared/install.sh into a new temp directory from # https://docs.openviking.net/dl and https://docs.openviking.ai/dl at the # same time. The two hosts serve the same documentation site and the same # downloads; the copy that arrives first is used, and the installer takes # the rest of its downloads from that host. OPENVIKING_DOWNLOAD_BASE names # other locations. # 2. Refuses to run a copy unless line 1 is a shebang and the first lines name # the OpenViking memory plugin installer. # 3. Runs it with bash as `install.sh --dist tos [--harness ] `, # reading input from the terminal, then deletes the temp directory and # exits with the installer's status. # The installer's own header lists the files it writes, the hosts it contacts # and the version check it makes; OPENVIKING_SKIP_VERSION_CHECK=1 skips that # check and installs the latest release. # # bootstrap-version: 1 harness="" is_installer() { head -n 1 "$1" | grep -q '^#!' && head -n 5 "$1" | grep -q 'OpenViking Memory Plugin shared installer' } # Leaves the installer in $workdir/install.sh and its location in $base. fetch_installer() { local asked=0 seen=0 n # OPENVIKING_TOS_BASE is the name earlier installers read. # shellcheck disable=SC2086 set -- ${OPENVIKING_DOWNLOAD_BASE:-${OPENVIKING_TOS_BASE:-https://docs.openviking.net/dl https://docs.openviking.ai/dl}} : >"$workdir/up" : >"$workdir/down" for base in "$@"; do asked=$((asked + 1)) ( if curl -fsSL --connect-timeout 10 -m 120 -o "$workdir/$asked.sh" "${base%/}/memory-plugin-shared/install.sh"; then printf '%s %s\n' "$asked" "${base%/}" >>"$workdir/up" else echo >>"$workdir/down" fi ) 2>"$workdir/$asked.err" & done while :; do while [ "$(wc -l <"$workdir/up")" -gt "$seen" ]; do seen=$((seen + 1)) read -r n base <&2 done [ "$((seen + $(wc -l <"$workdir/down")))" -lt "$asked" ] || break sleep 0.1 done cat "$workdir"/*.err >&2 echo "openviking: could not download the installer from: $*" >&2 return 1 } main() { local input # A directory of its own: the installer looks for its helpers next to itself. # Global, not local: the EXIT trap runs after main has returned. workdir="$(mktemp -d "${TMPDIR:-/tmp}/openviking-install.XXXXXX")" || return 1 trap 'rm -rf "$workdir"' EXIT fetch_installer || return 1 export OPENVIKING_DOWNLOAD_BASE="$base" export OPENVIKING_INSTALLER_REEXEC=0 if [ -n "$harness" ]; then set -- --harness "$harness" "$@" fi input=/dev/null if { true /dev/null; then input=/dev/tty fi bash "$workdir/install.sh" --dist tos "$@" <"$input" } main "$@"