Files
blackroad/scripts/memory-sync-daemon.sh
Alexa Amundson 78fbe80f2a Initial monorepo — everything BlackRoad in one place
bin/       230 CLI tools (ask-*, br-*, agent-*, roadid, carpool)
scripts/   99 automation scripts
fleet/     Node configs and deployment
workers/   Cloudflare Worker sources (roadpay, road-search, squad webhooks)
roadc/     RoadC programming language
roadnet/   Mesh network (5 APs, WireGuard)
operator/  Memory system scripts
config/    System configs
dotfiles/  Shell configs
docs/      Documentation

BlackRoad OS — Pave Tomorrow.

RoadChain-SHA2048: d1a24f55318d338b
RoadChain-Identity: alexa@sovereign
RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
2026-03-14 17:08:41 -05:00

433 lines
12 KiB
Bash
Executable File

#!/bin/bash
# BlackRoad Real-Time Memory Sync Daemon
# Enables multiple concurrent Claude instances to share memory in real-time
# Polls journal changes at 1ms intervals and broadcasts updates
set -e
VERSION="2.0.0-realtime"
# Configuration
MEMORY_DIR="$HOME/.blackroad/memory"
JOURNAL_DIR="$MEMORY_DIR/journals"
SYNC_DIR="$MEMORY_DIR/sync"
DAEMON_PID_FILE="$SYNC_DIR/daemon.pid"
POLL_INTERVAL=0.001 # 1ms
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
# Helper functions
log_info() {
echo -e "${BLUE}[SYNC]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SYNC]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[SYNC]${NC} $1"
}
log_error() {
echo -e "${RED}[SYNC]${NC} $1"
}
log_broadcast() {
echo -e "${CYAN}[BROADCAST]${NC} $1"
}
# Initialize sync infrastructure
init_sync() {
log_info "Initializing real-time sync system..."
mkdir -p "$SYNC_DIR/instances"
mkdir -p "$SYNC_DIR/broadcasts"
mkdir -p "$SYNC_DIR/checkpoints"
# Create instance registry
cat > "$SYNC_DIR/instance-registry.jsonl" <<EOF
{"timestamp":"$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)","action":"registry_init","details":"Real-time sync initialized"}
EOF
# Create sync config
cat > "$SYNC_DIR/sync-config.json" <<EOF
{
"version": "${VERSION}",
"poll_interval_ms": 1,
"max_instances": 100,
"broadcast_ttl_seconds": 60,
"checkpoint_interval_entries": 100
}
EOF
log_success "Sync infrastructure ready"
}
# Register Claude instance
register_instance() {
local instance_id="${1:-claude-$(date +%s)-$$}"
local instance_file="$SYNC_DIR/instances/${instance_id}.json"
local timestamp="$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)"
cat > "$instance_file" <<EOF
{
"instance_id": "${instance_id}",
"pid": $$,
"registered_at": "${timestamp}",
"last_seen": "${timestamp}",
"hostname": "$(hostname)",
"working_directory": "$(pwd)",
"journal_position": 0,
"status": "active"
}
EOF
# Log to instance registry
echo "{\"timestamp\":\"${timestamp}\",\"action\":\"instance_registered\",\"instance_id\":\"${instance_id}\",\"pid\":$$}" >> "$SYNC_DIR/instance-registry.jsonl"
echo "$instance_id"
}
# Update instance heartbeat
update_heartbeat() {
local instance_id="$1"
local journal_position="$2"
local instance_file="$SYNC_DIR/instances/${instance_id}.json"
if [ -f "$instance_file" ]; then
# Update last_seen and position using jq
local temp_file="${instance_file}.tmp"
jq --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)" \
--arg position "$journal_position" \
'.last_seen = $timestamp | .journal_position = ($position | tonumber)' \
"$instance_file" > "$temp_file" && mv "$temp_file" "$instance_file"
fi
}
# Get journal position (last line read)
get_journal_position() {
local instance_id="$1"
local instance_file="$SYNC_DIR/instances/${instance_id}.json"
if [ -f "$instance_file" ]; then
jq -r '.journal_position' "$instance_file" 2>/dev/null || echo "0"
else
echo "0"
fi
}
# Broadcast new entries to all instances
broadcast_entries() {
local start_line="$1"
local end_line="$2"
local broadcast_id="broadcast-$(date +%s%3N)"
local broadcast_file="$SYNC_DIR/broadcasts/${broadcast_id}.jsonl"
# Extract new entries
sed -n "${start_line},${end_line}p" "$JOURNAL_DIR/master-journal.jsonl" > "$broadcast_file"
# Add metadata
local entry_count=$((end_line - start_line + 1))
log_broadcast "New entries: ${entry_count} (lines ${start_line}-${end_line})"
# Cleanup old broadcasts (older than TTL)
find "$SYNC_DIR/broadcasts" -name "broadcast-*.jsonl" -mmin +1 -delete 2>/dev/null || true
}
# Watch journal and broadcast changes
watch_journal() {
local instance_id="$1"
local last_line_count=0
log_info "Starting real-time journal watcher (${POLL_INTERVAL}s polling)"
log_info "Instance: $instance_id"
if [ ! -f "$JOURNAL_DIR/master-journal.jsonl" ]; then
log_error "Master journal not found. Initialize memory system first."
return 1
fi
while true; do
# Get current line count
local current_line_count=$(wc -l < "$JOURNAL_DIR/master-journal.jsonl" 2>/dev/null || echo "0")
# Check if new entries exist
if [ "$current_line_count" -gt "$last_line_count" ]; then
local start_line=$((last_line_count + 1))
local end_line=$current_line_count
# Broadcast new entries
broadcast_entries "$start_line" "$end_line"
# Update position
update_heartbeat "$instance_id" "$current_line_count"
last_line_count=$current_line_count
else
# Just update heartbeat
update_heartbeat "$instance_id" "$last_line_count"
fi
# Poll at configured interval
sleep $POLL_INTERVAL
done
}
# Get real-time updates for specific instance
get_updates() {
local instance_id="$1"
local last_position=$(get_journal_position "$instance_id")
local current_line_count=$(wc -l < "$JOURNAL_DIR/master-journal.jsonl" 2>/dev/null || echo "0")
if [ "$current_line_count" -gt "$last_position" ]; then
local start_line=$((last_position + 1))
echo -e "${CYAN}[UPDATES]${NC} New entries available (${start_line}-${current_line_count}):"
echo ""
sed -n "${start_line},${current_line_count}p" "$JOURNAL_DIR/master-journal.jsonl" | \
jq -r '" [" + .timestamp + "] " + .action + ": " + .entity + " — " + .details'
# Update position
update_heartbeat "$instance_id" "$current_line_count"
else
echo "No new updates"
fi
}
# List active instances
list_instances() {
echo -e "${BLUE}╔════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ 🔄 Active Claude Instances ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════╝${NC}"
echo ""
if [ ! -d "$SYNC_DIR/instances" ]; then
log_warning "No instances directory found"
return 0
fi
local instance_count=0
for instance_file in "$SYNC_DIR/instances"/*.json; do
if [ -f "$instance_file" ]; then
local instance_id=$(jq -r '.instance_id' "$instance_file")
local pid=$(jq -r '.pid' "$instance_file")
local last_seen=$(jq -r '.last_seen' "$instance_file")
local position=$(jq -r '.journal_position' "$instance_file")
local status=$(jq -r '.status' "$instance_file")
# Check if process is still running
if ps -p "$pid" > /dev/null 2>&1; then
status="${GREEN}active${NC}"
else
status="${RED}dead${NC}"
fi
echo -e " ${GREEN}Instance:${NC} $instance_id"
echo -e " ${GREEN}PID:${NC} $pid (${status})"
echo -e " ${GREEN}Position:${NC} $position entries"
echo -e " ${GREEN}Last seen:${NC} $last_seen"
echo ""
((instance_count++))
fi
done
if [ $instance_count -eq 0 ]; then
log_warning "No active instances"
else
echo -e "Total: $instance_count instances"
fi
}
# Start daemon in background
start_daemon() {
if [ -f "$DAEMON_PID_FILE" ]; then
local old_pid=$(cat "$DAEMON_PID_FILE")
if ps -p "$old_pid" > /dev/null 2>&1; then
log_warning "Daemon already running (PID: $old_pid)"
return 0
else
log_warning "Removing stale PID file"
rm "$DAEMON_PID_FILE"
fi
fi
# Initialize if needed
if [ ! -f "$SYNC_DIR/sync-config.json" ]; then
init_sync
fi
# Register instance
local instance_id=$(register_instance "daemon-$(date +%s)")
# Start watcher in background
nohup "$0" _internal_watch "$instance_id" \
> "$SYNC_DIR/daemon.log" 2>&1 &
local daemon_pid=$!
echo "$daemon_pid" > "$DAEMON_PID_FILE"
log_success "Daemon started (PID: $daemon_pid, Instance: $instance_id)"
echo " Log: $SYNC_DIR/daemon.log"
}
# Stop daemon
stop_daemon() {
if [ ! -f "$DAEMON_PID_FILE" ]; then
log_warning "No daemon PID file found"
return 0
fi
local daemon_pid=$(cat "$DAEMON_PID_FILE")
if ps -p "$daemon_pid" > /dev/null 2>&1; then
log_info "Stopping daemon (PID: $daemon_pid)..."
kill "$daemon_pid"
rm "$DAEMON_PID_FILE"
log_success "Daemon stopped"
else
log_warning "Daemon not running (stale PID)"
rm "$DAEMON_PID_FILE"
fi
}
# Show daemon status
daemon_status() {
echo -e "${BLUE}╔════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ 🔄 Real-Time Sync Daemon Status ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════╝${NC}"
echo ""
if [ -f "$DAEMON_PID_FILE" ]; then
local daemon_pid=$(cat "$DAEMON_PID_FILE")
if ps -p "$daemon_pid" > /dev/null 2>&1; then
echo -e " ${GREEN}Status:${NC} Running ✅"
echo -e " ${GREEN}PID:${NC} $daemon_pid"
echo -e " ${GREEN}Poll interval:${NC} ${POLL_INTERVAL}s (1ms)"
# Show CPU/Memory usage
local ps_stats=$(ps -p "$daemon_pid" -o %cpu,%mem,vsz,rss | tail -1)
echo -e " ${GREEN}Resources:${NC} $ps_stats"
# Show recent log entries
if [ -f "$SYNC_DIR/daemon.log" ]; then
echo ""
echo -e "${BLUE}Recent activity:${NC}"
tail -5 "$SYNC_DIR/daemon.log" | sed 's/^/ /'
fi
else
echo -e " ${RED}Status:${NC} Dead ❌ (stale PID)"
fi
else
echo -e " ${YELLOW}Status:${NC} Not running"
fi
echo ""
}
# Show help
show_help() {
cat <<EOF
BlackRoad Real-Time Memory Sync Daemon v${VERSION}
USAGE:
memory-sync-daemon.sh <command> [options]
COMMANDS:
init Initialize sync infrastructure
start Start sync daemon (1ms polling)
stop Stop sync daemon
status Show daemon status
register [instance-id] Register new Claude instance
updates <instance-id> Get updates for instance
instances List all active instances
help Show this help
EXAMPLES:
# Start daemon
memory-sync-daemon.sh init
memory-sync-daemon.sh start
# Register Claude instance
INSTANCE_ID=\$(memory-sync-daemon.sh register "claude-session-1")
echo \$INSTANCE_ID
# Get real-time updates
memory-sync-daemon.sh updates \$INSTANCE_ID
# Monitor instances
memory-sync-daemon.sh instances
# Check daemon
memory-sync-daemon.sh status
SYNC LOCATIONS:
Instances: $SYNC_DIR/instances/
Broadcasts: $SYNC_DIR/broadcasts/
Daemon log: $SYNC_DIR/daemon.log
Registry: $SYNC_DIR/instance-registry.jsonl
REAL-TIME FEATURES:
✅ 1ms polling interval
✅ Lock-free concurrent reads
✅ Atomic append-only writes
✅ Automatic position tracking
✅ Instance heartbeats
✅ Broadcast to all instances
✅ Automatic cleanup
EOF
}
# Main command handler
case "${1:-help}" in
init)
init_sync
;;
start)
start_daemon
;;
stop)
stop_daemon
;;
status)
daemon_status
;;
register)
register_instance "${2:-}"
;;
updates)
if [ -z "$2" ]; then
log_error "Usage: $0 updates <instance-id>"
exit 1
fi
get_updates "$2"
;;
_internal_watch)
watch_journal "$2"
;;
instances)
list_instances
;;
help|--help|-h)
show_help
;;
*)
log_error "Unknown command: $1"
echo ""
show_help
exit 1
;;
esac