Skip to content

Instantly share code, notes, and snippets.

@thoroc
Last active November 21, 2025 11:54
Show Gist options
  • Select an option

  • Save thoroc/9d8e5b06cc85c7526258f90559af7840 to your computer and use it in GitHub Desktop.

Select an option

Save thoroc/9d8e5b06cc85c7526258f90559af7840 to your computer and use it in GitHub Desktop.
Check which models is currently set across all the Opencode related files on the system
#!/usr/bin/env bash
set -euo pipefail
shopt -s nullglob
# opencode-model-check.sh - Check currently used model in OpenCode logs
#
# Requirements:
# REQUIRED:
# - jq: JSON processor (https://jqlang.github.io/jq/)
# - grep: Text search utility (standard on all Unix systems)
# - Standard Unix tools: find, ls, du, basename, cut, sed, awk, head, tr, xargs
#
# OPTIONAL (automatically used if available):
# - rg (ripgrep): Faster text search (https://github.com/BurntSushi/ripgrep)
# Script automatically uses rg when available, falls back to grep
#
# Installation:
# • macOS: brew install jq ripgrep
# • Linux: apt-get install jq ripgrep (Debian/Ubuntu)
# yum install jq ripgrep (RHEL/CentOS)
# • mise: mise install jq ripgrep
#
# Usage:
# opencode-model-check.sh # Show current model
# opencode-model-check.sh gpt # Search for 'gpt' models
# opencode-model-check.sh --history # Show model usage history
# Tool availability checks
# jq: Required for JSON operations (no fallback)
# grep: Required for all operations (no fallback)
# rg (ripgrep): Optional, falls back to grep if not available
# Check for required tool: grep
if ! command -v grep >/dev/null 2>&1; then
echo "Error: grep is required but not found in PATH" >&2
echo "Please install grep or ensure it's in your PATH" >&2
exit 1
fi
# Check for required tool: jq
if ! command -v jq >/dev/null 2>&1; then
echo "Error: jq is required but not found in PATH" >&2
echo "" >&2
echo "Install jq using one of these methods:" >&2
echo " • macOS: brew install jq" >&2
echo " • Linux: apt-get install jq (Debian/Ubuntu)" >&2
echo " yum install jq (RHEL/CentOS)" >&2
echo " • mise: mise install jq" >&2
echo "" >&2
echo "Or download from: https://jqlang.github.io/jq/download/" >&2
exit 1
fi
# Check for optional tool: rg (ripgrep)
# Prefer ripgrep when available for better performance, fallback to grep
if command -v rg >/dev/null 2>&1; then
GREP_CMD="rg"
GREP_NO_FILENAME="-I" # ripgrep uses -I for --no-filename
GREP_BRACE="\{" # ripgrep requires escaped brace
else
GREP_CMD="grep"
GREP_NO_FILENAME="-h" # grep uses -h to suppress filename
GREP_BRACE="{" # grep uses literal brace
fi
# OpenCode directories
OPENCODE_CONFIG_DIR="${HOME}/.config/opencode"
OPENCODE_SHARE_DIR="${HOME}/.local/share/opencode"
OPENCODE_STATE_DIR="${HOME}/.local/state/opencode"
OPENCODE_CACHE_DIR="${HOME}/.cache/opencode"
LOG_DIR="${OPENCODE_SHARE_DIR}/log"
CONFIG_FILE="${OPENCODE_CONFIG_DIR}/opencode.json"
AUTH_FILE="${OPENCODE_SHARE_DIR}/auth.json"
SNAPSHOT_DIR="${OPENCODE_SHARE_DIR}/snapshot"
MODEL_STATE_FILE="${OPENCODE_STATE_DIR}/model.json"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Helper function to replace home directory with ~
tildify() {
sed "s|${HOME}|~|g"
}
usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS] [SEARCH_TERM]
Check currently used model in OpenCode or search for specific models.
OPTIONS:
-h, --help Show this help message
--history Show model usage history across all logs
--config Show model configuration from opencode.json
--all Show all unique models used
--dirs Show OpenCode directory locations
--providers Show configured authentication providers
--json Output current model information as JSON
EXAMPLES:
$(basename "$0") # Show current model
$(basename "$0") gpt # Find logs using GPT models
$(basename "$0") claude # Find logs using Claude models
$(basename "$0") --history # Show chronological model history
EOF
exit 0
}
show_directories() {
echo -e "${BLUE}OpenCode directories:${NC}"
echo
local dirs=(
"Config:${OPENCODE_CONFIG_DIR}"
"Data:${OPENCODE_SHARE_DIR}"
"State:${OPENCODE_STATE_DIR}"
"Cache:${OPENCODE_CACHE_DIR}"
"Logs:${LOG_DIR}"
"Snapshots:${SNAPSHOT_DIR}"
)
for dir_info in "${dirs[@]}"; do
local label="${dir_info%%:*}"
local path="${dir_info#*:}"
local display_path
display_path=$(echo "$path" | tildify)
if [[ -d "$path" ]]; then
local size
# For Data directory, exclude log/ and snapshot/ subdirectories from size calculation
if [[ "$label" == "Data" ]]; then
# Calculate size excluding log and snapshot subdirectories
# Use find to sum sizes of all files/dirs except log and snapshot
size=$(find "$path" -mindepth 1 -maxdepth 1 ! -name log ! -name snapshot -exec du -sk {} + 2>/dev/null | awk '{sum+=$1} END {
if (sum >= 1048576) printf "%.1fG\n", sum/1048576
else if (sum >= 1024) printf "%.0fM\n", sum/1024
else printf "%dK\n", sum
}')
else
size=$(du -sh "$path" 2>/dev/null | cut -f1 | tr -d ' ')
fi
echo -e " ${GREEN}✓${NC} ${label}: ${display_path} (${size})"
else
echo -e " ${RED}✗${NC} ${label}: ${display_path} (not found)"
fi
done
echo
}
show_providers() {
echo -e "${BLUE}Authentication providers:${NC}"
if [[ -f "$AUTH_FILE" ]]; then
echo
local providers
providers=$($GREP_CMD -o "\"[^\"]*\":[[:space:]]*$GREP_BRACE" "$AUTH_FILE" | cut -d'"' -f2)
if [[ -n "$providers" ]]; then
while IFS= read -r provider; do
local type
type=$($GREP_CMD -A1 "\"$provider\"" "$AUTH_FILE" | $GREP_CMD '"type"' | cut -d'"' -f4)
echo -e " ${GREEN}$provider${NC} (${type})"
done <<< "$providers"
else
echo " No providers configured"
fi
else
local display_path
display_path=$(echo "$AUTH_FILE" | tildify)
echo " Auth file not found: $display_path"
fi
echo
}
show_recent_models() {
if [[ -f "$MODEL_STATE_FILE" ]]; then
echo -e "${BLUE}Recent model selections:${NC}"
jq -r '.recent[] | " \(.providerID) → \(.modelID)"' "$MODEL_STATE_FILE" 2>/dev/null
echo
fi
}
check_config() {
local display_dir
display_dir=$(echo "$OPENCODE_CONFIG_DIR" | tildify)
echo -e "${BLUE}Configuration (${display_dir}):${NC}"
if [[ -f "$CONFIG_FILE" ]]; then
if $GREP_CMD -q '"model"' "$CONFIG_FILE" 2>/dev/null; then
$GREP_CMD -E '"model"|"provider"' "$CONFIG_FILE" | sed 's/^/ /'
else
echo " No explicit model configuration found (using default)"
fi
else
echo " Config file not found"
fi
echo
}
get_current_model() {
local latest_log
# Find the most recent log file
latest_log=$(find "$LOG_DIR" -name "*.log" -type f -print0 2>/dev/null | xargs -0 ls -t 2>/dev/null | head -1)
if [[ -z "$latest_log" ]]; then
echo -e "${RED}No log files found${NC}" >&2
return 1
fi
local model
model=$($GREP_CMD -o '"model":"[^"]*"' "$latest_log" 2>/dev/null | head -1 | cut -d'"' -f4 || true)
if [[ -n "$model" ]]; then
echo -e "${GREEN}Current model:${NC} ${YELLOW}$model${NC}"
echo -e "${BLUE}From log:${NC} $(basename "$latest_log")"
else
echo -e "${YELLOW}No model found in latest log${NC}"
echo -e "${BLUE}Latest log:${NC} $(basename "$latest_log")"
fi
}
show_history() {
echo -e "${BLUE}Model usage history:${NC}"
echo
local found=0
local logs=("$LOG_DIR"/*.log)
# Sort by modification time (newest first)
if [[ ${#logs[@]} -gt 0 && -f "${logs[0]}" ]]; then
while IFS= read -r -d '' log; do
local model
model=$($GREP_CMD -o '"model":"[^"]*"' "$log" 2>/dev/null | head -1 | cut -d'"' -f4 || true)
if [[ -n "$model" ]]; then
local timestamp
timestamp=$(basename "$log" .log)
echo -e " ${GREEN}$timestamp${NC} → ${YELLOW}$model${NC}"
found=1
fi
done < <(find "$LOG_DIR" -name "*.log" -type f -print0 2>/dev/null | xargs -0 ls -t 2>/dev/null | tr '\n' '\0')
fi
if [[ $found -eq 0 ]]; then
echo -e " ${YELLOW}No model information found in logs${NC}"
fi
}
show_all_models() {
echo -e "${BLUE}All unique models used:${NC}"
echo
local models
models=$($GREP_CMD $GREP_NO_FILENAME '"model":"[^"]*"' "$LOG_DIR"/*.log 2>/dev/null | \
$GREP_CMD -o '"model":"[^"]*"' | \
cut -d'"' -f4 | \
sort -u)
if [[ -n "$models" ]]; then
while IFS= read -r model; do
local count
count=$($GREP_CMD $GREP_NO_FILENAME -cF "\"model\":\"$model\"" "$LOG_DIR"/*.log 2>/dev/null | awk '{s+=$1} END {print s}')
echo -e " ${YELLOW}$model${NC} (used in $count requests)"
done <<< "$models"
else
echo -e " ${YELLOW}No models found in logs${NC}"
fi
}
search_model() {
local search_term="$1"
echo -e "${BLUE}Searching for models matching '${search_term}':${NC}"
echo
local found=0
local logs=("$LOG_DIR"/*.log)
# Sort by modification time (newest first)
if [[ ${#logs[@]} -gt 0 && -f "${logs[0]}" ]]; then
while IFS= read -r -d '' log; do
local model
model=$($GREP_CMD -o '"model":"[^"]*"' "$log" 2>/dev/null | head -1 | cut -d'"' -f4 || true)
if [[ -n "$model" ]] && [[ "$model" =~ $search_term ]]; then
local timestamp
timestamp=$(basename "$log" .log)
echo -e " ${GREEN}$timestamp${NC} → ${YELLOW}$model${NC}"
found=1
fi
done < <(find "$LOG_DIR" -name "*.log" -type f -print0 2>/dev/null | xargs -0 ls -t 2>/dev/null | tr '\n' '\0')
fi
if [[ $found -eq 0 ]]; then
echo -e " ${YELLOW}No matching models found${NC}"
fi
}
output_json() {
local latest_log
# Find the most recent log file
latest_log=$(find "$LOG_DIR" -name "*.log" -type f -print0 2>/dev/null | xargs -0 ls -t 2>/dev/null | head -1)
if [[ -z "$latest_log" ]]; then
echo '{"error": "No log files found"}' >&2
exit 1
fi
local model
local provider
local timestamp
model=$($GREP_CMD -o '"model":"[^"]*"' "$latest_log" 2>/dev/null | head -1 | cut -d'"' -f4 || true)
provider=$($GREP_CMD -o '"provider":"[^"]*"' "$latest_log" 2>/dev/null | head -1 | cut -d'"' -f4 || true)
timestamp=$(basename "$latest_log" .log)
# Build JSON output (jq is required and checked at script start)
jq -n \
--arg model "${model:-null}" \
--arg provider "${provider:-null}" \
--arg log "$timestamp" \
--arg log_path "$latest_log" \
'{
model: $model,
provider: $provider,
log: $log,
log_path: $log_path,
timestamp: $log
}'
}
# Main script
if [[ ! -d "$LOG_DIR" ]]; then
echo -e "${RED}Error: Log directory not found: $LOG_DIR${NC}" >&2
exit 1
fi
case "${1:-}" in
-h|--help)
usage
;;
--dirs)
show_directories
;;
--providers)
show_providers
;;
--config)
check_config
;;
--history)
show_history
;;
--all)
show_all_models
;;
--json)
output_json
;;
"")
show_directories
check_config
show_recent_models
show_providers
get_current_model
;;
*)
search_model "$1"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment