Restoring Simple Tasks
Every bundle in /home/joe/.hermes/backups/simple-tasks/ is self-describing and
verifiable on its own. Do not copy a live WAL database by hand; do not restore a
bundle that fails verify.
What a bundle contains
tasks.sqlite3 consistent online snapshot (SQLite backup API)
manifest.json created_at, health verdict, per-table row counts and SHA-256,
source hash, code and unit hashes
code/ app.py store.py importer.py scheduler.py ops.py
calendar_sync.py mcp_cal.py schema.sql index.html RESTORE.md
units/ simple-tasks*.service / *.timer definitions
RESTORE.md this file
Retention: 48 hourly auto bundles plus 30 days of dailies.
1. Verify before trusting
cd /home/joe/workspace/simple-tasks
python3 ops.py verify /home/joe/.hermes/backups/simple-tasks/<bundle>.tar.gzok: true means every member hash matched the manifest, the database passed
quick_check, integrity_check and foreign_key_check, and table counts equal
the manifest. Any other result: stop, keep the bundle, do not delete.
2. Rehearse the restore (never into the live path)
DRILL=$(mktemp -d /home/joe/.hermes/cache/scratch/restore.XXXXXX)
python3 ops.py restore-check <bundle>.tar.gz --dest "$DRILL" \
--live-db /home/joe/.local/share/simple-tasks/tasks.sqlite3drift_vs_live reports per-table identical flags: differences are expected for
tables that changed since the bundle was taken, and are the evidence you use to
decide whether restoring would lose newer edits.
Prove the runtime starts from the restored copy alone:
cd "$DRILL/code"
python3 app.py --host 127.0.0.1 --port 8680 --db "$DRILL/tasks.sqlite3" &
curl --fail --silent http://127.0.0.1:8680/api/health
kill %1{"ok": true, ...} and a rendered All view are the acceptance evidence. Stop the
process afterwards; never leave a second listener running.
3. Restore in place
Only with Joe’s decision, and only after step 2 shows no lost edits:
systemctl --user stop simple-tasks.service
cp /home/joe/.local/share/simple-tasks/tasks.sqlite3 \
/home/joe/.local/share/simple-tasks/tasks.sqlite3.pre-restore
# remove -wal/-shm siblings so the restored file is authoritative
mv <live>-wal <live>-wal.discard 2>/dev/null; mv <live>-shm <live>-shm.discard 2>/dev/null
python3 - <<'PY'
import tarfile, shutil
tarfile.open('<bundle>.tar.gz').extract('tasks.sqlite3', '/tmp/restore')
shutil.copy('/tmp/restore/tasks.sqlite3', '/home/joe/.local/share/simple-tasks/tasks.sqlite3')
PY
systemctl --user start simple-tasks.service
curl --fail --silent http://127.0.0.1:8672/api/healthThen check /api/status: mode, counts and last_backup must be coherent. Keep
tasks.sqlite3.pre-restore until Joe has used the app once.
4. What restore cannot bring back
- Edits made after the bundle was taken (compare
drift_vs_livefirst). - Memory: the guarded-memory archive is a separate bundle in
/home/joe/.hermes/backups/mnemosyne/with its own manifest, ledger and receipts. Restoring it without the current suppression ledger re-exposes forgotten facts — followguarded_memory_ops.pyand never drop the ledger.