Central repository for Claude Code session transcripts from multiple machines
Add these to your shell profile (~/.bashrc, ~/.zshrc, etc.):
# Claude Sync configuration export CLAUDE_SYNC_URL="https://claude.cee.wtf" export CLAUDE_SYNC_KEY="your-api-key-here" export CLAUDE_MACHINE_ID="$(hostname)" # or a custom name
Then reload your shell: source ~/.bashrc (or restart your terminal)
Save this to ~/.claude/hooks/sync-session.sh:
#!/bin/bash
# Claude Code session sync hook
# Uploads transcript to central server on session end and before compacts
: "${CLAUDE_SYNC_URL:=https://claude.cee.wtf}"
: "${CLAUDE_SYNC_KEY:=}"
: "${CLAUDE_MACHINE_ID:=$(hostname)}"
# Skip if no API key configured
[ -z "$CLAUDE_SYNC_KEY" ] && exit 0
# Read hook input from stdin
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty')
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')
# Validate required fields
[ -z "$SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] && exit 0
# Expand ~ in path
TRANSCRIPT_PATH="${TRANSCRIPT_PATH/#\~/$HOME}"
[ -f "$TRANSCRIPT_PATH" ] || exit 0
# Upload in background (don't block session exit)
curl -s -X POST "$CLAUDE_SYNC_URL/api/sessions" \
-H "X-API-Key: $CLAUDE_SYNC_KEY" \
-F "machine_id=$CLAUDE_MACHINE_ID" \
-F "session_id=$SESSION_ID" \
-F "transcript=@$TRANSCRIPT_PATH" \
--max-time 10 >/dev/null 2>&1 &
exit 0
Make it executable:
mkdir -p ~/.claude/hooks chmod +x ~/.claude/hooks/sync-session.sh
Edit ~/.claude/settings.json to add the hooks:
{
"hooks": {
"SessionEnd": [
{
"hooks": [{
"type": "command",
"command": "$HOME/.claude/hooks/sync-session.sh"
}]
}
],
"PreCompact": [
{
"hooks": [{
"type": "command",
"command": "$HOME/.claude/hooks/sync-session.sh"
}]
}
]
}
}
Why PreCompact? Long sessions compact multiple times. Uploading on each compact captures intermediate states, so if a session crashes you still have the last pre-compact snapshot. Same session_id overwrites previous upload.
Test the upload manually:
# Create a test transcript
echo '{"test":true}' > /tmp/test.jsonl
# Upload it
curl -X POST https://claude.cee.wtf/api/sessions \
-H "X-API-Key: $CLAUDE_SYNC_KEY" \
-F "machine_id=test" \
-F "session_id=test-$(date +%s)" \
-F "transcript=@/tmp/test.jsonl"
# List sessions to confirm (auth required)
curl -H "X-API-Key: $CLAUDE_SYNC_KEY" \
https://claude.cee.wtf/api/sessions
The hook only uploads sessions when they end. To bulk upload existing sessions from ~/.claude/projects/:
# Upload all existing sessions
for file in ~/.claude/projects/*/*.jsonl; do
[ -f "$file" ] || continue
session_id=$(basename "$file" .jsonl)
echo "Uploading $session_id..."
curl -s -X POST "$CLAUDE_SYNC_URL/api/sessions" \
-H "X-API-Key: $CLAUDE_SYNC_KEY" \
-F "machine_id=$CLAUDE_MACHINE_ID" \
-F "session_id=$session_id" \
-F "transcript=@$file"
done
This is only needed once per machine to backfill historical sessions. Future sessions will sync automatically.
Authentication: All API endpoints (except / and /api/healthz) require the X-API-Key header. Do NOT use Bearer authentication - use the header directly: X-API-Key: your-key
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/sessions |
Upload transcript |
GET |
/api/sessions |
List sessions (?machine_id=xxx&limit=100) |
GET |
/api/sessions/{id}/transcript |
Download raw JSONL |
GET |
/api/healthz |
Health check (no auth required) |
POST /api/sessions Content-Type: multipart/form-data X-API-Key: your-api-key machine_id: laptop-home session_id: abc123-def456 transcript: (file)
{
"status": "ok",
"session_id": "abc123-def456",
"machine_id": "laptop-home",
"file_size": 12345
}