testsAndMisc/python_pkg/archwiki_rag/install.sh
Krzysztof kuhy Rudnicki 86565bdef6 archwiki_rag: offline semantic search over the Arch Wiki
Indexes the arch-wiki-docs dump that is already on disk and exposes it
to the knowledge-rag MCP server, so Arch questions can be asked by
symptom ("why doesn't my systemd user unit see DISPLAY under i3")
rather than by page title, with no network round-trip at query time.

The one Arch-specific MCP server in the wild fetches pages over the
network and bundles pacman operations that duplicate the local yay-mcp.
This does neither: it only searches, against a local corpus.

install.sh installs its own dependencies, wires the MCP config and
registers a pacman hook so the index follows package updates. The
generated index is machine-specific and regenerable, so it is
gitignored rather than committed.

_reindex_entry runs under the knowledge-rag interpreter, where
mcp_server is importable and this repo's packages are not. Resolving
that import with importlib.import_module states the deferral outright
instead of a function-level import statement that reads as an oversight,
and the backend failure path now re-raises as SystemExit, so the
exit-code translation is explicit rather than a swallowed exception.
Both replace lint suppressions; the package carries none.

pylint runs in its own venv, so beautifulsoup4 and markdownify are
declared there too — being in meta/requirements.txt does not make them
resolvable to the hook.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YQLwdquDCNmWtvgi3Lk72J
2026-08-10 15:33:18 +02:00

131 lines
3.4 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# Install the offline Arch Wiki RAG corpus and its refresh hook.
#
# Installs dependencies, builds the corpus, and registers a pacman hook that
# refreshes it whenever `arch-wiki-docs` is upgraded.
# ============================================================================
set -euo pipefail
SCRIPT_NAME="$(basename "$0")"
PKG_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "${PKG_DIR}/../.." && pwd)"
readonly SCRIPT_NAME PKG_DIR REPO_ROOT
readonly STORE_DIR="${HOME}/.local/share/knowledge-rag-archwiki"
readonly REFRESH_BIN="/usr/local/bin/archwiki-rag-refresh"
readonly HOOK_PATH="/etc/pacman.d/hooks/95-archwiki-rag.hook"
readonly MCP_CONFIG="${HOME}/.claude/mcp-optional/archwiki.json"
usage() {
echo "Usage: $SCRIPT_NAME [--no-hook]"
echo "Options:"
echo " --no-hook Install dependencies and build the corpus, but skip the"
echo " pacman hook (which needs sudo)."
echo " -h, --help Show this help"
exit 0
}
INSTALL_HOOK=1
install_dependencies() {
echo "==> Installing dependencies"
# arch-wiki-docs is the corpus itself; the two Python packages do the
# HTML -> Markdown conversion.
sudo pacman -S --needed --noconfirm \
arch-wiki-docs \
python-beautifulsoup4 \
python-markdownify
}
write_mcp_config() {
echo "==> Writing MCP config: $MCP_CONFIG"
mkdir -p "$(dirname "$MCP_CONFIG")"
cat >"$MCP_CONFIG" <<EOF
{
"mcpServers": {
"archwiki": {
"type": "stdio",
"command": "${HOME}/.local/bin/knowledge-rag",
"args": [],
"env": {
"KNOWLEDGE_RAG_DIR": "${STORE_DIR}"
}
}
}
}
EOF
}
build_corpus() {
echo "==> Building corpus (this takes ~1 min for conversion)"
PYTHONPATH="$REPO_ROOT" python3 -m python_pkg.archwiki_rag sync --reindex
}
install_hook() {
echo "==> Installing pacman hook"
# The hook runs as root; this wrapper drops back to the invoking user and
# detaches the CPU-bound reindex so the pacman transaction is not blocked
# while the corpus re-embeds.
sudo tee "$REFRESH_BIN" >/dev/null <<EOF
#!/bin/bash
# Refresh the offline Arch Wiki RAG corpus. Installed by $SCRIPT_NAME.
set -euo pipefail
exec systemd-run --machine="${USER}@" --user --quiet --collect \\
--unit=archwiki-rag-refresh \\
--setenv=PYTHONPATH="$REPO_ROOT" \\
/usr/bin/python3 -m python_pkg.archwiki_rag sync --reindex
EOF
sudo chmod 755 "$REFRESH_BIN"
# Only Install/Upgrade/Remove are valid Operation values; an invalid hook
# aborts EVERY pacman transaction, so this file must stay minimal.
sudo mkdir -p "$(dirname "$HOOK_PATH")"
sudo tee "$HOOK_PATH" >/dev/null <<EOF
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = arch-wiki-docs
[Action]
Description = Refreshing offline Arch Wiki RAG corpus...
When = PostTransaction
Exec = $REFRESH_BIN
EOF
}
main() {
install_dependencies
write_mcp_config
build_corpus
if [[ "$INSTALL_HOOK" -eq 1 ]]; then
install_hook
else
echo "==> Skipping pacman hook (--no-hook)"
fi
echo "==> Done. Start a session with: claude-archwiki"
}
while [[ $# -gt 0 ]]; do
case $1 in
--no-hook)
INSTALL_HOOK=0
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
main "$@"