#!/bin/bash # This hook injects context on session startup to instruct Claude Code # to always use the knowledge skill for Claude Code related questions # Read input JSON INPUT_JSON=$(cat) # Set up basic environment export CLAUDE_HOME="$HOME/.claude" export CLAUDE_SESSION_ID=$(echo "$INPUT_JSON" | grep -o '"session_id":"[^"]*"' | cut -d'"' -f4) # Debug logging function - only logs if CLAUDE_HOOK_DEBUG_LOG is set debug_log() { if [ -n "$CLAUDE_HOOK_DEBUG_LOG" ]; then echo "$@" >> "$CLAUDE_HOOK_DEBUG_LOG" fi } debug_log "===== Starting claude-expert-sessionstart.sh Hook $(date) =====" debug_log "" debug_log "CLAUDE-SPECIFIC VARIABLES:" debug_log "CLAUDE_HOME: ${CLAUDE_HOME:-}" debug_log "CLAUDE_PROJECT_DIR: ${CLAUDE_PROJECT_DIR:-}" debug_log "CLAUDE_PLUGIN_ROOT: ${CLAUDE_PLUGIN_ROOT:-}" debug_log "CLAUDE_SESSION_ID: ${CLAUDE_SESSION_ID:-}" debug_log "CLAUDE_ENV_FILE: ${CLAUDE_ENV_FILE:-}" # Create CLAUDE_ENV_FILE if not set (workaround for Claude Code bug with plugin hooks) if [ -z "$CLAUDE_ENV_FILE" ] && [ -n "$CLAUDE_SESSION_ID" ] && [ -n "$CLAUDE_HOME" ]; then export CLAUDE_ENV_FILE="$CLAUDE_HOME/session-env/$CLAUDE_SESSION_ID/hook-0.sh" # Create the directory if it doesn't exist mkdir -p "$(dirname "$CLAUDE_ENV_FILE")" # Create the file if it doesn't exist touch "$CLAUDE_ENV_FILE" debug_log "✓ Created CLAUDE_ENV_FILE: $CLAUDE_ENV_FILE" fi # Shared utility function to update or add environment variables # Usage: set_env_var "VAR_NAME" "value" set_env_var() { local var_name="$1" local var_value="$2" # Validate inputs if [ -z "$var_name" ]; then debug_log "ERROR: Variable name is required" return 1 fi # Skip if CLAUDE_ENV_FILE is not set if [ -z "$CLAUDE_ENV_FILE" ]; then debug_log "WARNING: CLAUDE_ENV_FILE is not set, skipping ${var_name}" return 0 fi # Create the directory if it doesn't exist local env_dir env_dir="$(dirname "$CLAUDE_ENV_FILE")" if [ ! -d "$env_dir" ]; then mkdir -p "$env_dir" || { debug_log "ERROR: Failed to create directory: $env_dir" return 1 } fi # Create the file if it doesn't exist if [ ! -f "$CLAUDE_ENV_FILE" ]; then touch "$CLAUDE_ENV_FILE" || { debug_log "ERROR: Failed to create file: $CLAUDE_ENV_FILE" return 1 } fi # Build the export line local export_line="export ${var_name}=\"${var_value}\"" # Check if the variable already exists in the file if grep -q "^export ${var_name}=" "$CLAUDE_ENV_FILE"; then # Update existing variable using sed sed -i "s|^export ${var_name}=.*|${export_line}|" "$CLAUDE_ENV_FILE" debug_log "Updated ${var_name} in ${CLAUDE_ENV_FILE}" else # Append new variable echo "$export_line" >> "$CLAUDE_ENV_FILE" debug_log "Added ${var_name} to ${CLAUDE_ENV_FILE}" fi return 0 } # Set environment variables if [ -n "$CLAUDE_ENV_FILE" ]; then debug_log "" debug_log "Setting environment variables in CLAUDE_ENV_FILE..." # Set CLAUDE_SESSION_ID set_env_var "CLAUDE_SESSION_ID" "$CLAUDE_SESSION_ID" debug_log "" debug_log "✓ Environment variables updated" if [ -n "$CLAUDE_HOOK_DEBUG_LOG" ]; then debug_log "CLAUDE_ENV_FILE contents:" cat "$CLAUDE_ENV_FILE" >> "$CLAUDE_HOOK_DEBUG_LOG" 2>&1 fi else debug_log "" debug_log "⚠ WARNING: CLAUDE_ENV_FILE is not set!" fi debug_log "" debug_log "Hook execution completed successfully" debug_log "" # ============================================================================ # CLAUDE-DOCS CLI INSTALLATION AND UPDATE MANAGEMENT # ============================================================================ INSTALL_STATUS="" INSTALL_ERROR="" LAST_UPDATE_CHECK_FILE="$CLAUDE_HOME/.claude-docs-last-check" UPDATE_CHECK_INTERVAL_HOURS=24 # Function to check if we should run update check (throttling) should_check_updates() { if [[ ! -f "$LAST_UPDATE_CHECK_FILE" ]]; then return 0 # First run fi local last_check last_check=$(cat "$LAST_UPDATE_CHECK_FILE" 2>/dev/null || echo "0") local now=$(date +%s) local age=$((now - last_check)) local hours=$((age / 3600)) if [[ $hours -lt $UPDATE_CHECK_INTERVAL_HOURS ]]; then return 1 # Too soon fi return 0 # Time to check } # Check if claude-docs is installed if command -v claude-docs &>/dev/null; then debug_log "✓ claude-docs is installed" # Get local version LOCAL_VERSION=$(claude-docs --version 2>/dev/null | tr -d '[:space:]') debug_log "Local version: $LOCAL_VERSION" # Only check for updates if throttle allows if should_check_updates; then debug_log "Checking for updates (last check > 24h ago)..." # Check GitHub for latest version (with timeout) GITHUB_VERSION=$(curl -s --max-time 5 https://api.github.com/repos/dkmaker/claude-docs-cli/releases/latest 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | tr -d 'v' | tr -d '[:space:]') if [ -n "$GITHUB_VERSION" ] && [ "$LOCAL_VERSION" != "$GITHUB_VERSION" ]; then debug_log "Update available: $LOCAL_VERSION -> $GITHUB_VERSION" debug_log "Attempting to update..." # Get download URL DOWNLOAD_URL=$(curl -s --max-time 5 https://api.github.com/repos/dkmaker/claude-docs-cli/releases/latest 2>/dev/null | grep "browser_download_url.*tgz" | cut -d '"' -f 4) if [ -n "$DOWNLOAD_URL" ]; then # Attempt update if npm install -g "$DOWNLOAD_URL" &>/dev/null; then NEW_VERSION=$(claude-docs --version 2>/dev/null | tr -d '[:space:]') INSTALL_STATUS="✅ Updated claude-docs: $LOCAL_VERSION → $NEW_VERSION" debug_log "✓ Update successful" # Update check timestamp on success date +%s > "$LAST_UPDATE_CHECK_FILE" else INSTALL_STATUS="⚠️ Failed to update claude-docs (currently running v$LOCAL_VERSION)" debug_log "✗ Update failed" fi else debug_log "Could not fetch download URL" fi else debug_log "claude-docs is up to date (v$LOCAL_VERSION)" # Update check timestamp date +%s > "$LAST_UPDATE_CHECK_FILE" fi else debug_log "Skipping update check (checked within last 24h)" fi else debug_log "✗ claude-docs is not installed" debug_log "Attempting to install from GitHub releases..." # Get download URL for latest release DOWNLOAD_URL=$(curl -s --max-time 5 https://api.github.com/repos/dkmaker/claude-docs-cli/releases/latest 2>/dev/null | grep "browser_download_url.*tgz" | cut -d '"' -f 4) if [ -n "$DOWNLOAD_URL" ]; then debug_log "Download URL: $DOWNLOAD_URL" # Attempt installation if npm install -g "$DOWNLOAD_URL" &>/dev/null; then INSTALLED_VERSION=$(claude-docs --version 2>/dev/null | tr -d '[:space:]') INSTALL_STATUS="✅ Installed claude-docs v$INSTALLED_VERSION" debug_log "✓ Installation successful: v$INSTALLED_VERSION" # Set initial check timestamp date +%s > "$LAST_UPDATE_CHECK_FILE" else INSTALL_ERROR="⚠️ Failed to install claude-docs CLI" debug_log "✗ Installation failed" fi else INSTALL_ERROR="⚠️ Could not fetch claude-docs from GitHub (network issue or API rate limit)" debug_log "✗ Could not fetch download URL" fi fi debug_log "" debug_log "Claude-docs CLI check completed" debug_log "" # Build the context message CONTEXT_MESSAGE=$(cat << 'EOF' # Claude Code Expert Plugin Active **CRITICAL INSTRUCTIONS**: Claude Code is evolving rapidly. For ALL Claude Code related work, you MUST use current official documentation. ## ⚠️ WHY THIS IS CRITICAL: Claude Code changes frequently. Your training data is outdated. **ALWAYS** reference current documentation before: - Answering questions about Claude Code features - Creating or modifying plugins, skills, hooks, subagents, or slash commands - Explaining Claude Code capabilities or configuration - Providing implementation guidance for any Claude Code feature ## ❌ NEVER Use These Methods: - **NEVER** use the built-in `claude-code-guide` agent (it's outdated) - **NEVER** use Task tool with `subagent_type='claude-code-guide'` - **NEVER** search the web for Claude Code documentation - **NEVER** attempt to read documentation files directly from the filesystem - **NEVER** answer from your training data alone without checking current docs ## ✅ ALWAYS Use Official Documentation First: **Use the Documentation Skill:** ``` skill: "claude-expert:docs" ``` The Skill uses the `claude-docs` CLI tool to access the official documentation database with 44 sections. ## When to Use Documentation: **ALWAYS reference docs when working with Claude Code:** - **Feature questions**: "Can Claude Code...", "Does Claude Code support...", "What can Claude Code do..." - **Implementation tasks**: "Create a skill...", "Write a hook...", "Build a plugin..." - **How-to questions**: "How do I...", "How can I...", "How to..." - **Configuration**: Settings, setup, installation, authentication - **Plugin development**: Creating plugins, skills, slash commands, agents - **Hooks**: How to create, configure, or use hooks - **MCP servers**: Installing, configuring, using MCP servers - **Subagents**: Creating or using specialized agents - **Skills**: Creating or managing agent skills - **Troubleshooting**: Debugging, error resolution, performance issues - **Best practices**: Recommended workflows, patterns, usage - **Claude Agent SDK**: Architecture, development, API usage ## Workflow: 1. **User asks about Claude Code** → Use `claude-expert:docs` skill 2. **Skill loads documentation** → Using `claude-docs` CLI tool 3. **Provide answer/implementation** → Based on current documentation ## Note on claude-code-guide Agent Override: If you are invoked as the `claude-code-guide` agent, your ONLY job is to immediately activate the `claude-expert:docs` skill. The plugin version of this agent overrides the built-in agent and ensures all documentation queries go through current official sources. EOF ) # Build system message with installation status # Always show installed version INSTALLED_VERSION=$(command -v claude-docs &>/dev/null && claude-docs --version 2>/dev/null | tr -d '[:space:]' || echo "not installed") SYSTEM_MESSAGE=" ✅ Claude Code Expert plugin loaded 📚 claude-docs v${INSTALLED_VERSION}" if [ -n "$INSTALL_STATUS" ]; then SYSTEM_MESSAGE="${SYSTEM_MESSAGE} ${INSTALL_STATUS}" fi if [ -n "$INSTALL_ERROR" ]; then SYSTEM_MESSAGE="${SYSTEM_MESSAGE} ${INSTALL_ERROR} 💡 Install manually: npm install -g \$(curl -s https://api.github.com/repos/dkmaker/claude-docs-cli/releases/latest | grep \"browser_download_url.*tgz\" | cut -d '\"' -f 4)" fi # Output JSON with hookSpecificOutput format jq -n \ --arg context "$CONTEXT_MESSAGE" \ --arg sysmsg "$SYSTEM_MESSAGE" \ '{ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: $context }, systemMessage: $sysmsg }' debug_log "JSON output generated successfully" exit 0