Recovery Method: OpenClaw Session JSONL Files via Fly SSH

Recovery Method: OpenClaw Session JSONL Files via Fly SSH

Why this works

OpenClaw writes every conversation to session JSONL files at /data/agents/main/sessions/ on each bot’s Fly machine. These files persist on the /data volume independently of Discord — deleting a Discord channel does NOT delete the bot’s local session records.

Steps

1. Get the session index

fly ssh console --app mangrove-{botname} -C "cat /data/agents/main/sessions/sessions.json"

This maps channel display names to session IDs. Search for the channel name in displayName or groupChannel fields. Example entry:

"agent:main:discord:channel:1482308244964774120": {
    "displayName": "discord:1479164061533863949#scammaster-corleone",
    "groupChannel": "#scammaster-corleone",
    "sessionId": "47af0e90-2c57-4d55-9227-fa3dc7e38e9b",
    "sessionFile": "/data/agents/main/sessions/47af0e90-2c57-4d55-9227-fa3dc7e38e9b.jsonl"
}

2. Pull the session JSONL

fly ssh console --app mangrove-{botname} -C "cat /data/agents/main/sessions/{sessionId}.jsonl" > recovered.jsonl

3. Parse the JSONL

Each line is a JSON record. Records with "type":"message" contain the conversation:

  • message.role = user (incoming Discord messages) or assistant (bot responses)
  • message.content = text string or array of content blocks with type: "text"
  • timestamp = ISO 8601 timestamp

Records with "type":"session" are session metadata. Records with "type":"toolResult" are tool call results.

Incorporating into a cron job

Periodically SSH into each bot’s Fly machine, pull sessions.json and all *.jsonl session files, and push them to Firebase RTDB (e.g. at session_backups/{botname}/). This way even if a channel is deleted AND the Fly machine is redeployed/destroyed, the conversation data survives in Firebase.

The data_push.py daemon on the gateway already does a version of this but only captures the latest session — a full backup should capture all session files from every bot machine.

Precedent: #scammaster-corleone (2026-03-15)

  • Channel deleted by Corleone; daily Discord scraper (6 AM) missed it; Discord API returned 404
  • Successfully recovered full 594KB / 160-record conversation from mangrove-scammaster Fly machine
  • Also recovered 5 other sessions from that bot (DMs, #protocols, #general, #ejbot-scammaster, #scammaster-corleone-recover)

Discord API limitations (confirmed)

  • GET /channels/{id} → 404 for deleted channels
  • Audit log: deletion metadata only, no message content
  • Guild search: doesn’t index deleted channel messages
  • GDPR data request: 30+ days, only returns messages authored by requesting account