893 lines
30 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# ============================================================================
# Clawdbot Memory System — One-Command Installer v2.0
# https://github.com/BusyBee3333/clawdbot-memory-system
#
# Usage:
# bash install.sh # Interactive install
# bash install.sh --dry-run # Preview changes without applying
# bash install.sh --uninstall # Remove memory system config
# ============================================================================
VERSION="2.0.0"
# --- Colors & Formatting ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
# --- State ---
DRY_RUN=false
UNINSTALL=false
CLAWDBOT_DIR=""
WORKSPACE_DIR=""
CONFIG_FILE=""
AGENTS_FILE=""
MEMORY_DIR=""
PROVIDER=""
API_KEY=""
INSTALL_ORG_SYSTEM=false
INSTALL_AUTO_SCAFFOLD=false
INSTALL_GIT_BACKUP=false
CHANGES_MADE=()
FILES_INDEXED=0
EXISTING_MEMORY_FILES=0
# --- Parse Args ---
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
--uninstall) UNINSTALL=true ;;
--help|-h)
echo "Clawdbot Memory System Installer v${VERSION}"
echo ""
echo "Usage:"
echo " bash install.sh Interactive install"
echo " bash install.sh --dry-run Preview changes without applying"
echo " bash install.sh --uninstall Remove memory system config"
exit 0
;;
*)
echo -e "${RED}Unknown option: $arg${NC}"
echo "Use --help for usage information."
exit 1
;;
esac
done
# --- Helper Functions ---
info() { echo -e "${BLUE}${NC} $1"; }
success() { echo -e "${GREEN}${NC} $1"; }
warn() { echo -e "${YELLOW}⚠️${NC} $1"; }
error() { echo -e "${RED}${NC} $1"; }
step() { echo -e "\n${BOLD}${MAGENTA}$1${NC}"; }
detail() { echo -e " ${DIM}$1${NC}"; }
dry() { echo -e " ${CYAN}[dry-run]${NC} $1"; }
jake() { echo -e " ${YELLOW}⭐ Jake's choice${NC}"; }
banner() {
echo ""
echo -e "${BOLD}${MAGENTA}"
echo " ╔══════════════════════════════════════════════╗"
echo " ║ 🧠 Clawdbot Memory System v${VERSION}"
echo " ║ Never lose context to compaction again ║"
echo " ╚══════════════════════════════════════════════╝"
echo -e "${NC}"
}
# --- Detect Clawdbot Installation ---
detect_clawdbot() {
step "STEP 1/9 — 🔍 Detecting Clawdbot installation..."
for dir in "$HOME/.clawdbot" "$HOME/.openclaw" "$HOME/.moltbot"; do
if [[ -d "$dir" ]]; then
CLAWDBOT_DIR="$dir"
break
fi
done
if [[ -z "$CLAWDBOT_DIR" ]]; then
error "Clawdbot installation not found!"
echo ""
echo " Looked in: ~/.clawdbot, ~/.openclaw, ~/.moltbot"
echo " Make sure Clawdbot is installed first: https://docs.clawd.bot/getting-started"
exit 1
fi
success "Found Clawdbot at ${BOLD}${CLAWDBOT_DIR}${NC}"
CONFIG_FILE="${CLAWDBOT_DIR}/clawdbot.json"
if [[ ! -f "$CONFIG_FILE" ]]; then
for name in "openclaw.json" "moltbot.json"; do
if [[ -f "${CLAWDBOT_DIR}/${name}" ]]; then
CONFIG_FILE="${CLAWDBOT_DIR}/${name}"
break
fi
done
fi
if [[ ! -f "$CONFIG_FILE" ]]; then
error "Config file not found at ${CONFIG_FILE}"
echo " Run 'clawdbot doctor' first to initialize your setup."
exit 1
fi
success "Found config at ${BOLD}${CONFIG_FILE}${NC}"
WORKSPACE_DIR=$(python3 -c "
import json, os
with open('${CONFIG_FILE}') as f:
cfg = json.load(f)
ws = cfg.get('agents', {}).get('defaults', {}).get('workspace', '')
if not ws:
ws = os.path.expanduser('~') + '/' + os.path.basename('${CLAWDBOT_DIR}') + '/workspace'
print(os.path.expanduser(ws))
" 2>/dev/null || echo "${CLAWDBOT_DIR}/workspace")
if [[ ! -d "$WORKSPACE_DIR" ]]; then
warn "Workspace directory not found at ${WORKSPACE_DIR}"
if $DRY_RUN; then
dry "Would create workspace directory"
else
mkdir -p "$WORKSPACE_DIR"
success "Created workspace directory"
fi
fi
success "Workspace: ${BOLD}${WORKSPACE_DIR}${NC}"
MEMORY_DIR="${WORKSPACE_DIR}/memory"
AGENTS_FILE="${WORKSPACE_DIR}/AGENTS.md"
}
# --- Check Dependencies ---
check_deps() {
step "STEP 2/9 — 🔧 Checking dependencies..."
if ! command -v jq &>/dev/null; then
warn "jq is not installed (needed for safe JSON config patching)"
if command -v brew &>/dev/null; then
read -rp " Install with Homebrew? [Y/n] " yn
yn=${yn:-Y}
if [[ "$yn" =~ ^[Yy] ]]; then
if $DRY_RUN; then
dry "Would run: brew install jq"
else
brew install jq
success "jq installed"
fi
else
error "jq is required. Install: brew install jq"
exit 1
fi
else
error "jq required: https://jqlang.github.io/jq/download/"
exit 1
fi
else
success "jq found: $(jq --version)"
fi
if ! command -v clawdbot &>/dev/null; then
if command -v openclaw &>/dev/null; then
alias clawdbot=openclaw
success "openclaw CLI found"
elif command -v moltbot &>/dev/null; then
alias clawdbot=moltbot
success "moltbot CLI found"
else
warn "clawdbot CLI not found — index build will be skipped"
fi
else
success "clawdbot CLI found"
fi
}
# --- Check Existing Memory Files ---
check_existing() {
step "STEP 3/9 — 📂 Checking existing memory files..."
if [[ -d "$MEMORY_DIR" ]]; then
EXISTING_MEMORY_FILES=$(find "$MEMORY_DIR" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
if [[ "$EXISTING_MEMORY_FILES" -gt 0 ]]; then
info "Found ${BOLD}${EXISTING_MEMORY_FILES}${NC} existing memory files — they'll be preserved and indexed"
echo ""
echo -e " ${DIM}Existing files:${NC}"
find "$MEMORY_DIR" -name "*.md" -type f 2>/dev/null | while read -r f; do
echo -e " ${DIM}$(basename "$f")${NC}"
done
else
info "Memory directory exists but is empty"
fi
else
info "No existing memory directory — will create one"
fi
if [[ -f "${WORKSPACE_DIR}/MEMORY.md" ]]; then
info "Found existing MEMORY.md — will be included in index"
fi
}
# --- Core Memory System Confirmation ---
confirm_core() {
step "STEP 4/9 — 🧠 Core Memory System"
echo ""
echo -e " ${BOLD}This installs:${NC}"
echo -e " ${GREEN}${NC} Daily log system — agent writes ${CYAN}memory/YYYY-MM-DD.md${NC} each session"
echo -e " capturing decisions, preferences, project progress, and blockers"
echo -e " ${GREEN}${NC} SQLite vector search index — semantic search over all memory files"
echo -e " (finds context even when wording differs, <100ms)"
echo -e " ${GREEN}${NC} Hybrid search — 70% vector similarity + 30% keyword matching"
echo -e " ${GREEN}${NC} Pre-compaction auto-flush — auto-saves context BEFORE session"
echo -e " compacts, so your agent never gets amnesia"
echo -e " ${GREEN}${NC} Agent instructions — tells your agent when and how to use memory"
echo -e " ${GREEN}${NC} Config patch — adds memorySearch settings without touching your"
echo -e " existing config (backs up first)"
echo ""
echo -e " ${DIM}Cost: ~\$0.50/month (OpenAI) or free (Gemini free tier / local)${NC}"
echo ""
jake
echo ""
read -rp " Install core memory system? [Y/n] " yn
yn=${yn:-Y}
if [[ ! "$yn" =~ ^[Yy] ]]; then
error "Core memory system is required. Exiting."
exit 0
fi
success "Core memory system will be installed"
}
# --- Choose Embedding Provider ---
choose_provider() {
step "STEP 5/9 — 🤖 Choose your embedding provider"
echo ""
echo -e " How should your agent generate search embeddings?"
echo ""
echo -e " ${BOLD}1)${NC} ${GREEN}OpenAI${NC} ${DIM}— fast, cheap (~\$0.02/M tokens), best quality${NC}"
jake
echo ""
echo -e " ${BOLD}2)${NC} ${BLUE}Gemini${NC} ${DIM}— free tier available, good quality${NC}"
echo ""
echo -e " ${BOLD}3)${NC} ${YELLOW}Local${NC} ${DIM}— fully offline, no API key, slower first build${NC}"
echo ""
read -rp " Choose [1/2/3] (default: 1): " choice
choice=${choice:-1}
case "$choice" in
1) PROVIDER="openai" ;;
2) PROVIDER="gemini" ;;
3) PROVIDER="local" ;;
*)
warn "Invalid choice, defaulting to OpenAI"
PROVIDER="openai"
;;
esac
success "Selected: ${BOLD}${PROVIDER}${NC}"
if [[ "$PROVIDER" == "openai" ]]; then
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
info "Found OPENAI_API_KEY in environment"
else
echo ""
echo -e " ${DIM}OpenAI API key is needed for embeddings.${NC}"
echo -e " ${DIM}Get one at: https://platform.openai.com/api-keys${NC}"
echo -e " ${DIM}(Press Enter to skip — you can set OPENAI_API_KEY env var later)${NC}"
echo ""
read -rsp " OpenAI API Key: " API_KEY
echo ""
[[ -n "$API_KEY" ]] && success "API key provided" || warn "No key — set OPENAI_API_KEY before using memory search"
fi
elif [[ "$PROVIDER" == "gemini" ]]; then
if [[ -n "${GEMINI_API_KEY:-}" ]]; then
info "Found GEMINI_API_KEY in environment"
else
echo ""
echo -e " ${DIM}Gemini API key is needed for embeddings.${NC}"
echo -e " ${DIM}Get one at: https://aistudio.google.com/apikey${NC}"
echo -e " ${DIM}(Press Enter to skip — you can set GEMINI_API_KEY env var later)${NC}"
echo ""
read -rsp " Gemini API Key: " API_KEY
echo ""
[[ -n "$API_KEY" ]] && success "API key provided" || warn "No key — set GEMINI_API_KEY before using memory search"
fi
fi
}
# --- Organization System (Optional) ---
offer_org_system() {
step "STEP 6/9 — 📁 Organization System (optional add-on)"
echo ""
echo -e " ${BOLD}This adds a project organization framework on top of memory:${NC}"
echo ""
echo -e " ${GREEN}📁 Project Quickstart${NC}"
echo -e " When you start any new project, your agent automatically creates"
echo -e " structured tracking files with consistent naming so everything"
echo -e " is searchable and organized from day one."
echo ""
echo -e " ${GREEN}🔬 Research Intel System${NC}"
echo -e " For ongoing monitoring (competitors, markets, trends). Current week's"
echo -e " intel stays detailed at top, older weeks auto-compress to summaries."
echo -e " Agent checks these before making strategic recommendations."
echo ""
echo -e " ${GREEN}📊 Project Tracking${NC}"
echo -e " Standardized stages, blockers, decisions, and handoffs. Never lose"
echo -e " track of where a project stands across sessions."
echo ""
echo -e " ${GREEN}🏷️ Tag Convention${NC}"
echo -e " Consistent file naming (${CYAN}{project}-progress.md${NC},"
echo -e " ${CYAN}{project}-research-intel.md${NC}) so memory search groups"
echo -e " everything by project automatically."
echo ""
jake
echo ""
read -rp " Install the organization system? [Y/n] " yn
yn=${yn:-Y}
if [[ "$yn" =~ ^[Yy] ]]; then
INSTALL_ORG_SYSTEM=true
success "Organization system will be installed"
else
info "Skipping organization system (you can add it later by re-running the installer)"
fi
}
# --- Auto-Scaffold for New Projects ---
offer_auto_scaffold() {
if ! $INSTALL_ORG_SYSTEM; then return; fi
step "STEP 7/9 — 🚀 New Project Auto-Scaffold"
echo ""
echo -e " ${BOLD}When enabled, your agent auto-creates files for new projects.${NC}"
echo ""
echo -e " Example: You say ${DIM}\"Let's start a competitor analysis for Acme Corp\"${NC}"
echo -e " Agent automatically creates:"
echo -e " ${CYAN}memory/acme-corp-progress.md${NC} ${DIM}(project tracking)${NC}"
echo -e " ${CYAN}memory/acme-corp-research-intel.md${NC} ${DIM}(intel rotation)${NC}"
echo ""
echo -e " Your agent will ask which templates apply before creating:"
echo -e " • Progress tracker? ${DIM}(almost always yes)${NC}"
echo -e " • Research intel? ${DIM}(if monitoring/research is involved)${NC}"
echo -e " • Contacts tracker? ${DIM}(if other people are involved)${NC}"
echo ""
jake
echo ""
read -rp " Enable auto-scaffold for new projects? [Y/n] " yn
yn=${yn:-Y}
if [[ "$yn" =~ ^[Yy] ]]; then
INSTALL_AUTO_SCAFFOLD=true
success "Auto-scaffold enabled"
else
info "Skipping auto-scaffold"
fi
}
# --- Git Backup ---
offer_git_backup() {
step "STEP 8/9 — 💾 Git Backup"
echo ""
echo -e " ${BOLD}Back up memory files to git for version history and offsite safety.${NC}"
echo ""
echo -e " Your agent will be instructed to run:"
echo -e " ${DIM}cd ~/.clawdbot/workspace && git add -A && git commit -m \"backup\" && git push${NC}"
echo -e " at the end of each session or major milestone."
echo ""
echo -e " ${DIM}If your workspace isn't a git repo yet, you'll need to:${NC}"
echo -e " ${DIM} cd ~/.clawdbot/workspace && git init && git remote add origin <your-repo-url>${NC}"
echo ""
jake
echo ""
read -rp " Include git backup instructions? [Y/n] " yn
yn=${yn:-Y}
if [[ "$yn" =~ ^[Yy] ]]; then
INSTALL_GIT_BACKUP=true
success "Git backup instructions will be included"
else
info "Skipping git backup"
fi
}
# --- Setup Memory Directory & Templates ---
setup_memory_dir() {
step "STEP 9/9 — 📝 Installing..."
echo ""
info "Setting up memory directory and templates..."
if $DRY_RUN; then
[[ ! -d "$MEMORY_DIR" ]] && dry "Would create ${MEMORY_DIR}/"
dry "Would copy template files"
$INSTALL_ORG_SYSTEM && dry "Would copy organization templates"
return
fi
# Create memory directory
if [[ ! -d "$MEMORY_DIR" ]]; then
mkdir -p "$MEMORY_DIR"
success "Created ${MEMORY_DIR}/"
CHANGES_MADE+=("Created memory/ directory")
fi
# Determine template source
local script_dir
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local templates_dir="${script_dir}/templates"
local base_url="https://raw.githubusercontent.com/BusyBee3333/clawdbot-memory-system/main/templates"
# If running from curl (no local templates dir), download them
if [[ ! -d "$templates_dir" ]]; then
templates_dir=$(mktemp -d)
for tmpl in TEMPLATE-daily.md TEMPLATE-research-intel.md TEMPLATE-project-tracking.md TEMPLATE-contacts.md; do
curl -sL "${base_url}/${tmpl}" -o "${templates_dir}/${tmpl}" 2>/dev/null || true
done
fi
# Always copy daily template
if [[ -f "${templates_dir}/TEMPLATE-daily.md" ]] && [[ ! -f "${MEMORY_DIR}/TEMPLATE-daily.md" ]]; then
cp "${templates_dir}/TEMPLATE-daily.md" "${MEMORY_DIR}/TEMPLATE-daily.md"
success "Added template: TEMPLATE-daily.md"
CHANGES_MADE+=("Added TEMPLATE-daily.md")
fi
# Copy org system templates if selected
if $INSTALL_ORG_SYSTEM; then
for tmpl in TEMPLATE-research-intel.md TEMPLATE-project-tracking.md TEMPLATE-contacts.md; do
if [[ -f "${templates_dir}/${tmpl}" ]] && [[ ! -f "${MEMORY_DIR}/${tmpl}" ]]; then
cp "${templates_dir}/${tmpl}" "${MEMORY_DIR}/${tmpl}"
success "Added template: ${tmpl}"
CHANGES_MADE+=("Added ${tmpl}")
fi
done
fi
# Create today's daily log
local today
today=$(date +%Y-%m-%d)
if [[ ! -f "${MEMORY_DIR}/${today}.md" ]]; then
cat > "${MEMORY_DIR}/${today}.md" << EOF
# Daily Log — ${today}
## What We Worked On
- Installed Clawdbot Memory System 🧠
## Decisions Made
- Chose ${PROVIDER} for embeddings
$(${INSTALL_ORG_SYSTEM} && echo "- Enabled organization system with project scaffolding" || true)
$(${INSTALL_GIT_BACKUP} && echo "- Set up git backup for memory files" || true)
## Next Steps
- Start using the memory system naturally — agent writes daily logs
- Check memory/ directory for accumulated context over time
## Open Questions / Blockers
- (none)
## Notable Context
Memory system installed and indexed. Agent will now persist important context
across sessions and search it automatically before answering questions.
EOF
success "Created today's daily log: ${today}.md"
CHANGES_MADE+=("Created daily log ${today}.md")
fi
}
# --- Patch clawdbot.json ---
patch_config() {
info "Patching clawdbot.json..."
local existing_provider
existing_provider=$(jq -r '.agents.defaults.memorySearch.provider // empty' "$CONFIG_FILE" 2>/dev/null || true)
if [[ -n "$existing_provider" ]]; then
info "memorySearch already configured (provider: ${existing_provider})"
read -rp " Overwrite with new provider ($PROVIDER)? [y/N] " yn
yn=${yn:-N}
if [[ ! "$yn" =~ ^[Yy] ]]; then
info "Keeping existing config"
return
fi
fi
if $DRY_RUN; then
dry "Would patch clawdbot.json with memorySearch (${PROVIDER})"
return
fi
cp "$CONFIG_FILE" "${CONFIG_FILE}.pre-memory-backup"
success "Backed up config → clawdbot.json.pre-memory-backup"
local memory_config
case "$PROVIDER" in
openai)
memory_config='{"provider":"openai","model":"text-embedding-3-small","query":{"hybrid":{"enabled":true,"vectorWeight":0.7,"textWeight":0.3,"candidateMultiplier":4}}}'
[[ -n "$API_KEY" ]] && memory_config=$(echo "$memory_config" | jq --arg key "$API_KEY" '. + {remote: {apiKey: $key}}')
;;
gemini)
memory_config='{"provider":"gemini","model":"gemini-embedding-001"}'
[[ -n "$API_KEY" ]] && memory_config=$(echo "$memory_config" | jq --arg key "$API_KEY" '. + {remote: {apiKey: $key}}')
;;
local)
memory_config='{"provider":"local","fallback":"none"}'
;;
esac
local tmp_file
tmp_file=$(mktemp)
jq --argjson ms "$memory_config" '.agents.defaults.memorySearch = ((.agents.defaults.memorySearch // {}) * $ms)' "$CONFIG_FILE" > "$tmp_file"
if jq empty "$tmp_file" 2>/dev/null; then
mv "$tmp_file" "$CONFIG_FILE"
success "Added memorySearch config (provider: ${PROVIDER})"
CHANGES_MADE+=("Patched clawdbot.json (${PROVIDER} embeddings)")
else
rm -f "$tmp_file"
error "Failed to patch config — restoring backup"
cp "${CONFIG_FILE}.pre-memory-backup" "$CONFIG_FILE"
exit 1
fi
}
# --- Patch AGENTS.md ---
patch_agents() {
info "Updating AGENTS.md..."
if [[ -f "$AGENTS_FILE" ]] && grep -q "Memory System (auto-added by clawdbot-memory-system" "$AGENTS_FILE" 2>/dev/null; then
info "AGENTS.md already contains memory instructions — updating"
# Remove old section before re-adding
python3 -c "
import re
with open('${AGENTS_FILE}') as f:
content = f.read()
content = re.sub(r'\n*## Memory System \(auto-added by clawdbot-memory-system.*?\n(?=## [^M]|\Z)', '\n', content, flags=re.DOTALL)
with open('${AGENTS_FILE}', 'w') as f:
f.write(content.rstrip() + '\n')
" 2>/dev/null || true
fi
if $DRY_RUN; then
dry "Would append memory + org instructions to AGENTS.md"
return
fi
# Build the patch content
local patch=""
patch+="
## Memory System (auto-added by clawdbot-memory-system installer v${VERSION})
### Mandatory Memory Recall
Before answering ANY question about prior work, decisions, dates, people, preferences, or context from previous sessions:
1. Run \`memory_search\` with a relevant query
2. Use \`memory_get\` to pull specific lines if needed
3. Check today's daily log: \`memory/YYYY-MM-DD.md\`
4. Check yesterday's log if today's is sparse
5. Only say \"I don't recall\" if memory search returns nothing
### Daily Memory Log
- Write to \`memory/YYYY-MM-DD.md\` throughout the session
- Log: decisions made, user preferences discovered, project progress, action items, blockers
- Be specific — future-you needs exact details, not vague summaries
- Include: names, URLs, version numbers, error messages, config values — anything painful to re-discover
- On session start, read today + yesterday's logs to restore context
### Pre-Compaction Flush
When you sense a session is getting long or receive a compaction warning:
- Write ALL important unsaved context to today's daily log immediately
- Include: what we were working on, where we left off, any pending decisions, partial results
- This is your last chance before amnesia — be thorough, not brief"
if $INSTALL_ORG_SYSTEM; then
patch+="
### Organization System — Project Files
When starting any new project or workstream, create structured tracking files:
**File naming convention:** \`memory/{project-slug}-{type}.md\`
- \`{project-slug}\`: lowercase, hyphenated (e.g., \`acme-analysis\`, \`competitor-intel\`)
- \`{type}\`: one of \`progress\`, \`research-intel\`, \`contacts\`
**Templates available in memory/ directory:**
- \`TEMPLATE-project-tracking.md\` — stages, blockers, decisions, next steps
- \`TEMPLATE-research-intel.md\` — weekly intel rotation with auto-compression
- \`TEMPLATE-contacts.md\` — people, roles, access levels"
fi
if $INSTALL_AUTO_SCAFFOLD; then
patch+="
### Auto-Scaffold for New Projects
When the user says anything like \"start a new project\", \"let's work on X\", or \"begin tracking Y\":
1. Ask which templates apply:
- Progress tracker? (almost always yes)
- Research intel? (if monitoring/research is involved)
- Contacts tracker? (if other people are involved)
2. Create the files using the naming convention: \`memory/{project-slug}-{type}.md\`
3. Copy from the templates in memory/ directory
4. Replace {placeholders} with actual project details
5. Add the project to today's daily log under \"What We Worked On\"
6. Confirm what was created and what each file is for"
fi
patch+="
### Research Intel System
For ongoing research/monitoring projects:
- Store in: \`memory/{project}-research-intel.md\`
- Current week's detailed intel at TOP of file
- Compressed 1-3 sentence summaries of previous weeks at BOTTOM
- Weekly: compress last week to summary, add new detailed intel at top
- When asked about action items or strategy, check active research intel files first"
if $INSTALL_GIT_BACKUP; then
patch+="
### Git Backup Habit
End of each session or major milestone:
\`\`\`bash
cd ~/.clawdbot/workspace && git add -A && git commit -m \"session backup: \$(date +%Y-%m-%d)\" && git push
\`\`\`
This keeps identity, memory, and progress backed up offsite. Remind the user if they haven't backed up recently."
fi
if [[ -f "$AGENTS_FILE" ]]; then
echo "" >> "$AGENTS_FILE"
echo "$patch" >> "$AGENTS_FILE"
else
echo "$patch" > "$AGENTS_FILE"
fi
success "Updated AGENTS.md with memory instructions"
$INSTALL_ORG_SYSTEM && success "Added organization system to AGENTS.md"
$INSTALL_AUTO_SCAFFOLD && success "Added auto-scaffold instructions to AGENTS.md"
$INSTALL_GIT_BACKUP && success "Added git backup habit to AGENTS.md"
CHANGES_MADE+=("Updated AGENTS.md")
}
# --- Build Index ---
build_index() {
info "Building memory search index..."
if $DRY_RUN; then
dry "Would run: clawdbot memory index --verbose"
return
fi
if ! command -v clawdbot &>/dev/null; then
warn "clawdbot CLI not in PATH — skipping index build"
detail "Run manually: clawdbot memory index --verbose"
return
fi
echo -e "${DIM}"
if clawdbot memory index --verbose 2>&1; then
echo -e "${NC}"
success "Index built successfully"
else
echo -e "${NC}"
warn "Index build had issues — run 'clawdbot memory status --deep' to check"
fi
FILES_INDEXED=$(find "$MEMORY_DIR" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
[[ -f "${WORKSPACE_DIR}/MEMORY.md" ]] && FILES_INDEXED=$((FILES_INDEXED + 1))
}
# --- Review & Confirm ---
review_confirm() {
echo ""
echo -e "${BOLD}${CYAN}"
echo " ╔══════════════════════════════════════════════╗"
echo " ║ 📋 Review Before Installing ║"
echo " ╚══════════════════════════════════════════════╝"
echo -e "${NC}"
echo ""
echo -e " ${BOLD}Will install:${NC}"
echo ""
echo -e " ${GREEN}${NC} Core Memory System"
echo -e " ${DIM}• memory/ directory with daily log template${NC}"
echo -e " ${DIM}• SQLite vector search (${PROVIDER} embeddings)${NC}"
echo -e " ${DIM}• Pre-compaction auto-flush${NC}"
echo -e " ${DIM}• Agent instructions in AGENTS.md${NC}"
if $INSTALL_ORG_SYSTEM; then
echo ""
echo -e " ${GREEN}${NC} Organization System"
echo -e " ${DIM}• Project tracking template${NC}"
echo -e " ${DIM}• Research intel template${NC}"
echo -e " ${DIM}• Contacts template${NC}"
echo -e " ${DIM}• Tag naming convention${NC}"
else
echo ""
echo -e " ${DIM}⏭️ Organization System (skipped)${NC}"
fi
if $INSTALL_AUTO_SCAFFOLD; then
echo ""
echo -e " ${GREEN}${NC} Auto-Scaffold for New Projects"
fi
if $INSTALL_GIT_BACKUP; then
echo ""
echo -e " ${GREEN}${NC} Git Backup Instructions"
fi
echo ""
echo -e " ${BOLD}Config changes:${NC}"
echo -e " ${DIM}• clawdbot.json → adding memorySearch config${NC}"
echo -e " ${DIM}• AGENTS.md → appending memory instructions${NC}"
echo -e " ${DIM}• Backup: clawdbot.json.pre-memory-backup${NC}"
if [[ "$EXISTING_MEMORY_FILES" -gt 0 ]]; then
echo ""
echo -e " ${BOLD}Migration:${NC}"
echo -e " ${DIM}${EXISTING_MEMORY_FILES} existing memory files will be preserved and indexed${NC}"
fi
echo ""
read -rp " Proceed with installation? [Y/n] " yn
yn=${yn:-Y}
if [[ ! "$yn" =~ ^[Yy] ]]; then
info "Installation cancelled"
exit 0
fi
}
# --- Print Summary ---
print_summary() {
echo ""
echo -e "${BOLD}${GREEN}"
echo " ╔══════════════════════════════════════════════╗"
echo " ║ 🎉 Installation Complete! ║"
echo " ╚══════════════════════════════════════════════╝"
echo -e "${NC}"
if [[ ${#CHANGES_MADE[@]} -gt 0 ]]; then
echo -e " ${BOLD}Changes made:${NC}"
for change in "${CHANGES_MADE[@]}"; do
echo -e " ${GREEN}${NC} ${change}"
done
echo ""
fi
if [[ "$EXISTING_MEMORY_FILES" -gt 0 ]]; then
echo -e " ${BOLD}Migration:${NC}"
echo -e " 📁 ${EXISTING_MEMORY_FILES} existing memory files preserved and indexed"
echo ""
fi
echo -e " ${BOLD}Index:${NC}"
echo -e " 📊 ${FILES_INDEXED} memory files indexed"
echo -e " 🤖 Provider: ${PROVIDER}"
echo ""
echo -e " ${BOLD}${CYAN}Next steps:${NC}"
echo ""
echo -e " ${BOLD}1.${NC} Restart the gateway to apply config changes:"
echo -e " ${DIM}clawdbot gateway restart${NC}"
echo ""
echo -e " ${BOLD}2.${NC} Start chatting! Your agent will now:"
echo -e " • Write daily logs to ${CYAN}memory/YYYY-MM-DD.md${NC}"
echo -e " • Search memories before answering about prior work"
echo -e " • Flush context before compaction (no more amnesia!)"
if $INSTALL_ORG_SYSTEM; then
echo -e " • Create structured files when you start new projects"
fi
echo ""
echo -e " ${BOLD}3.${NC} Test it! Ask your agent:"
echo -e " ${DIM}\"What did we work on today?\"${NC}"
if $INSTALL_AUTO_SCAFFOLD; then
echo -e " ${DIM}\"Start a new project called competitor analysis\"${NC}"
fi
echo ""
echo -e " ${BOLD}4.${NC} Verify anytime:"
echo -e " ${DIM}clawdbot memory status --deep${NC}"
echo ""
if [[ -n "$API_KEY" ]]; then
echo -e " ${YELLOW}⚠️ Your API key was saved to clawdbot.json.${NC}"
echo -e " ${DIM} Alternatively, set as env var and remove from config.${NC}"
echo ""
fi
echo -e " ${DIM}Your agent will NEVER forget again. ᕕ( ᐛ )ᕗ${NC}"
echo ""
echo -e " ${DIM}Problems? https://github.com/BusyBee3333/clawdbot-memory-system#troubleshooting${NC}"
echo ""
}
# --- Uninstall ---
do_uninstall() {
banner
step "🗑️ Uninstalling Clawdbot Memory System..."
detect_clawdbot
echo ""
warn "This will:"
echo " • Remove memorySearch config from clawdbot.json"
echo " • Remove memory instructions from AGENTS.md"
echo ""
echo -e " ${BOLD}This will NOT delete your memory/ files.${NC}"
echo " Your memories are safe — only the config is removed."
echo ""
read -rp " Continue? [y/N] " yn
yn=${yn:-N}
[[ ! "$yn" =~ ^[Yy] ]] && { info "Cancelled"; exit 0; }
if [[ -f "$CONFIG_FILE" ]] && jq -e '.agents.defaults.memorySearch' "$CONFIG_FILE" &>/dev/null; then
cp "$CONFIG_FILE" "${CONFIG_FILE}.pre-uninstall-backup"
local tmp_file; tmp_file=$(mktemp)
jq 'del(.agents.defaults.memorySearch)' "$CONFIG_FILE" > "$tmp_file"
if jq empty "$tmp_file" 2>/dev/null; then
mv "$tmp_file" "$CONFIG_FILE"
success "Removed memorySearch from config"
else
rm -f "$tmp_file"; error "Failed to patch config"
fi
fi
if [[ -f "$AGENTS_FILE" ]] && grep -q "Memory System (auto-added by clawdbot-memory-system" "$AGENTS_FILE" 2>/dev/null; then
cp "$AGENTS_FILE" "${AGENTS_FILE}.pre-uninstall-backup"
python3 -c "
import re
with open('${AGENTS_FILE}') as f:
content = f.read()
content = re.sub(r'\n*## Memory System \(auto-added by clawdbot-memory-system.*', '', content, flags=re.DOTALL)
with open('${AGENTS_FILE}', 'w') as f:
f.write(content.rstrip() + '\n')
" 2>/dev/null || true
success "Removed memory instructions from AGENTS.md"
fi
echo ""
success "Uninstall complete"
echo -e " ${DIM}Memory files preserved. Run 'clawdbot gateway restart' to apply.${NC}"
exit 0
}
# ============================================================================
# Main Flow
# ============================================================================
[[ "$UNINSTALL" == true ]] && do_uninstall
banner
$DRY_RUN && echo -e " ${CYAN}${BOLD}Running in dry-run mode — no changes will be made${NC}\n"
# Interactive onboarding
detect_clawdbot # Step 1
check_deps # Step 2
check_existing # Step 3
confirm_core # Step 4
choose_provider # Step 5
offer_org_system # Step 6
offer_auto_scaffold # Step 7
offer_git_backup # Step 8
review_confirm # Review
# Install
setup_memory_dir # Step 9 (creates dirs + templates)
patch_config # (patches clawdbot.json)
patch_agents # (patches AGENTS.md)
build_index # (builds SQLite index)
# Done
if $DRY_RUN; then
echo ""
echo -e " ${CYAN}${BOLD}Dry run complete — no changes were made.${NC}"
echo -e " ${DIM}Run without --dry-run to apply.${NC}"
echo ""
else
print_summary
fi