Skip to content

Instantly share code, notes, and snippets.

@cmdruid
Created March 6, 2025 02:39
Show Gist options
  • Save cmdruid/f3835a7a900eeb281507d5d2fb98109f to your computer and use it in GitHub Desktop.
Save cmdruid/f3835a7a900eeb281507d5d2fb98109f to your computer and use it in GitHub Desktop.
Used Grok 3 to write a command-line tool for using Grok on my codebase.
#!/bin/bash
# Configuration defaults
API_KEY="your-xai-api-key-here" # Default API key (overridden by config or env)
API_URL="https://api.x.ai/v1/chat/completions"
CODEBASE_FILE="/tmp/grok_codebase.txt"
SESSION_FILE="$PWD/grok_session_$(date +%Y%m%d_%H%M%S).txt" # Default in current directory
SOURCE_PATH=""
MODEL="grok-3-latest" # Default model
CONTEXT=""
CURRENT_DIR="$PWD" # Current working directory where script is executed
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Directory where script resides
CONFIG_FILE=""
# Function to display usage
usage() {
echo "Usage: $0 source_path [-s session_file] [-m model] [-c config_file]"
echo " source_path: Specify the source path or file to compact (required)"
echo " -s: Specify the session file to use (optional, defaults to a timestamped file in current directory)"
echo " -m: Specify the Grok model to use (optional, defaults to grok-3-latest)"
echo " -c: Specify a config file to use (optional, defaults to .grokconfig in current directory or script directory)"
exit 1
}
# Function to load config file
load_config() {
local config_path="$1"
if [ -f "$config_path" ]; then
echo "Loading config from $config_path..."
while IFS='=' read -r key value; do
# Skip empty lines and comments
[[ -z "$key" || "$key" =~ ^# ]] && continue
# Remove leading/trailing whitespace
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
case "$key" in
API_KEY) [ -z "$API_KEY_SET" ] && API_KEY="$value";;
MODEL) [ -z "$MODEL_SET" ] && MODEL="$value";;
esac
done < "$config_path"
fi
}
# Parse command-line options (-s, -m, and -c are optional)
while getopts "s:m:c:" opt; do
case $opt in
s) SESSION_FILE="$CURRENT_DIR/$OPTARG";;
m) MODEL="$OPTARG"; MODEL_SET="1";;
c) CONFIG_FILE="$OPTARG";;
?) usage;;
esac
done
# Shift past the options to get positional arguments
shift $((OPTIND-1))
# Check if source_path (first positional argument) is provided
if [ -z "$1" ]; then
echo "Error: source_path is required."
usage
fi
SOURCE_PATH="$1"
# Load config file: -c first, then current directory, then script directory
if [ -n "$CONFIG_FILE" ]; then
load_config "$CONFIG_FILE"
else
# Try current directory first
CONFIG_FILE="$CURRENT_DIR/.grokconfig"
if [ -f "$CONFIG_FILE" ]; then
load_config "$CONFIG_FILE"
else
# Fall back to script directory
CONFIG_FILE="$SCRIPT_DIR/.grokconfig"
load_config "$CONFIG_FILE"
fi
fi
# Ensure required tools are installed
command -v curl >/dev/null 2>&1 || { echo "curl is required but not installed. Please install it."; exit 1; }
command -v jq >/dev/null 2>&1 || { echo "jq is required for JSON parsing. Please install it."; exit 1; }
# Function to compact codebase with .grokignore support from current directory
compact_codebase() {
echo "Compacting codebase from $SOURCE_PATH into $CODEBASE_FILE..."
> "$CODEBASE_FILE" # Clear the file
local grokignore="$CURRENT_DIR/.grokignore"
local exclude_patterns=()
# Check .grokignore in the current directory (where the script is run)
if [ -f "$grokignore" ]; then
echo "Found .grokignore in $CURRENT_DIR, applying exclusions..."
while IFS= read -r line || [ -n "$line" ]; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
exclude_patterns+=("-not" "-name" "$line")
done < "$grokignore"
fi
# Handle if SOURCE_PATH is a file or directory
if [ -f "$SOURCE_PATH" ]; then
# If it's a file, include it directly unless excluded
if [[ ! "$SOURCE_PATH" =~ .grokignore ]] && ! echo "$SOURCE_PATH" | grep -q -f "$grokignore" 2>/dev/null; then
echo "=== $SOURCE_PATH ===" >> "$CODEBASE_FILE"
cat "$SOURCE_PATH" >> "$CODEBASE_FILE"
echo -e "\n" >> "$CODEBASE_FILE"
fi
elif [ -d "$SOURCE_PATH" ]; then
# If it's a directory, use find with exclusions
find "$SOURCE_PATH" -type f -not -name ".grokignore" "${exclude_patterns[@]}" | while read -r file; do
echo "=== $file ===" >> "$CODEBASE_FILE"
cat "$file" >> "$CODEBASE_FILE"
echo -e "\n" >> "$CODEBASE_FILE"
done
else
echo "Error: $SOURCE_PATH is neither a file nor a directory."
exit 1
fi
echo "Codebase compacted. Size: $(wc -l < "$CODEBASE_FILE") lines"
}
# Function to send query to Grok API
query_grok() {
local prompt="$1"
# Prepare the messages
local system_message="You are Grok 3, built by xAI. Analyze the provided codebase and assist with the user's question."
local user_message="Here's my codebase:\n$(cat "$CODEBASE_FILE")\n\nPrevious context: $CONTEXT\n\nQuestion: $prompt"
# Use jq to construct the JSON payload safely
local payload=$(jq -n \
--arg system "$system_message" \
--arg user "$user_message" \
--arg model "$MODEL" \
'{
messages: [
{role: "system", content: $system},
{role: "user", content: $user}
],
model: $model,
stream: false,
temperature: 0
}')
# Send request to Grok API
response=$(curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "$payload")
# Extract the response
answer=$(echo "$response" | jq -r '.choices[0].message.content' 2>/dev/null || echo "Error parsing response: $response")
echo "$answer"
# Update context with this interaction
CONTEXT="$CONTEXT\nUser: $prompt\nGrok: $answer"
# Save to session file
echo -e "=== $(date '+%Y-%m-%d %H:%M:%S') ===\nPrompt: $prompt\nResponse: $answer\n" >> "$SESSION_FILE"
}
# Function to load previous session
load_session() {
if [ -f "$SESSION_FILE" ]; then
echo "Loading previous session from $SESSION_FILE..."
CONTEXT=$(cat "$SESSION_FILE" | grep -v "^===")
fi
}
# Main loop
main() {
echo "Grok Codebase Query Tool"
echo "Source path/file: $SOURCE_PATH"
echo "Session file: $SESSION_FILE"
echo "Model: $MODEL"
echo "API Key: ${API_KEY:0:4}... (truncated for security)"
echo "Enter 'exit' to quit"
# Compact codebase once at start
compact_codebase
# Load previous session if exists
load_session
while true; do
echo -n "Enter your prompt: "
read -r prompt
if [ "$prompt" = "exit" ]; then
echo "Saving session and exiting..."
break
fi
if [ -z "$prompt" ]; then
echo "Please enter a non-empty prompt."
continue
fi
echo "Querying Grok..."
query_grok "$prompt"
echo
done
# Clean up temporary file
rm -f "$CODEBASE_FILE"
}
# Trap Ctrl+C to ensure cleanup
trap 'echo "Interrupted. Saving session..."; rm -f "$CODEBASE_FILE"; exit 0' INT
# Run the main function
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment