Working around Claude resilience issues
0
.claude.json settings keep getting wiped#
Claude Code intermittently erases configurations from ~/.claude.json — no error, no warning, settings just gone. Set up a launchd file watcher to catch it in the act.
The watcher#
~/Library/LaunchAgents/com.user.watch-claude-json.plist — copies a timestamped snapshot into ~/.claude/backups/ on every write to the file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.watch-claude-json</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>cp ~/.claude.json ~/.claude/backups/claude-json-$(date +%Y%m%d-%H%M%S).json</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Users/user/.claude.json</string>
</array>
</dict>
</plist>
Scripts#
diff-backups.sh — diffs consecutive snapshots and pipes into diffnav:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="${1:-$(dirname "$0")}"
mapfile -t files < <(ls -1 "$BACKUP_DIR"/claude-json-*.json 2>/dev/null | sort)
if [[ ${#files[@]} -lt 2 ]]; then
echo "Need at least 2 backup files to diff."
exit 1
fi
combined=""
for ((i = 0; i < ${#files[@]} - 1; i++)); do
older="${files[$i]}"
newer="${files[$i + 1]}"
older_name=$(basename "$older")
newer_name=$(basename "$newer")
chunk=$(diff -u --label "a/${older_name}" --label "b/${newer_name}" "$older" "$newer" 2>/dev/null || true)
if [[ -n "$chunk" ]]; then
combined+="${chunk}
"
fi
done
if [[ -z "$combined" ]]; then
echo "No differences found between any consecutive backups."
exit 0
fi
echo "$combined" | diffnav
prune-backups.sh — removes snapshots identical to the previous one (DRY_RUN=true to preview):
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="${1:-$(dirname "$0")}"
DRY_RUN="${DRY_RUN:-false}"
mapfile -t files < <(ls -1 "$BACKUP_DIR"/claude-json-*.json 2>/dev/null | sort)
if [[ ${#files[@]} -lt 2 ]]; then
echo "Need at least 2 backup files to compare."
exit 0
fi
removed=0
for ((i = 1; i < ${#files[@]}; i++)); do
prev="${files[$i - 1]}"
curr="${files[$i]}"
if cmp -s "$prev" "$curr"; then
if [[ "$DRY_RUN" == "true" ]]; then
echo "[dry-run] would remove $(basename "$curr") (same as $(basename "$prev"))"
else
echo "Removing $(basename "$curr") (same as $(basename "$prev"))"
rm "$curr"
fi
removed=$((removed + 1))
fi
done
if [[ "$DRY_RUN" == "true" ]]; then
echo "Done. ${removed} duplicate(s) would be removed."
else
echo "Done. ${removed} duplicate(s) removed."
fi