google-doc-backup exports Google Docs, Sheets, and Slides into local Office-format backups. The current service path is tenant-scoped, uv-managed, and prefers the local gws Google Workspace CLI with the legacy direct Google API path kept as a fallback.
The default local backup target is:
/mnt/e/SyncThing/Cloud/Google-Docs
- My Drive, under
My Drive/whenmy_drive_root_mode = "scoped". - Files shared with the authenticated user, under
Shared With Me/<owner>/. - Shared Drives visible to the authenticated user, under
Shared drives/<drive name>/. - Standalone Apps Script projects under
AppScript/whenclaspis installed and scripts are enabled.
Google-native files are exported as:
- Docs:
.docx - Sheets:
.xlsx - Slides:
.pptx
Backup filenames include a source marker before the Office extension, such as
Report.gdoc.docx, Data.gsheet.xlsx, or Deck.gslides.pptx. If a
Google-native file title already ends with the same Office extension, that
title suffix is stripped first so Deck.pptx becomes Deck.gslides.pptx, not
Deck.pptx.gslides.pptx.
Each run writes a JSON manifest under the tenant state directory so service runs can be audited without reading the backup tree directly.
Use uv for the Python environment:
uv sync
uv run python download_google_doc.pyw --helpThe repo also exposes the historical script entry point directly. Prefer uv run python download_google_doc.pyw ... until the CLI is split into importable modules.
Tenant config lives outside the repo:
~/.config/google-doc-backup/tenants/<tenant>.toml
Default state lives outside the repo:
~/.local/state/google-doc-backup/tenants/<tenant>/
Example default tenant config:
tenant = "default"
backend = "auto"
backup_root = "/mnt/e/SyncThing/Cloud/Google-Docs"
include_my_drive = true
include_shared_with_me = true
include_shared_drives = true
include_apps_script = true
my_drive_root_mode = "scoped"
staggered = 5
dry_run = falseBackend modes:
auto: usegwsfirst, then fall back to the direct API path when thegwsreadiness probe fails.gws: requiregws.direct-api: use the legacy PyDrive/direct Google API path.
Inspect resolved config without authenticating:
uv run python download_google_doc.pyw --tenant default --show-configRun readiness checks:
uv run python download_google_doc.pyw --tenant default --doctorRun a no-write backup plan:
uv run python download_google_doc.pyw --tenant default --dry-run --show-configRun a backup manually:
uv run python download_google_doc.pyw --tenant defaultDisable Apps Script backup when clasp is unavailable:
uv run python download_google_doc.pyw --tenant default --no-scriptsRecover local gws auth with:
gws auth sync-gogIf the shell wrapper cannot find gog, set GWS_GOG_BIN to the real binary path and retry.
Install or update the user-scoped systemd timer:
uv run python download_google_doc.pyw --tenant default --install-user-servicePreview generated service files without writing them:
uv run python download_google_doc.pyw --tenant default --install-user-service --service-dry-runThe default timer runs daily at 03:30 local time. On this workstation the installed service currently includes --no-scripts because clasp is optional and was not available during setup.
Inspect the timer:
systemctl --user list-timers 'google-doc-backup@default.timer' --no-pagerTimestamped backup retention can be configured per tenant or overridden per run:
staggered = 5staggered = 5 keeps five staggered historical exports per file using the existing retention algorithm. newest = N keeps the newest N timestamped backups instead; if both are configured, newest wins.
CLI overrides:
uv run python download_google_doc.pyw --tenant default --staggered 5
uv run python download_google_doc.pyw --tenant default --newest 5Older backups may have My Drive folders directly at the backup root. Plan a migration into the scoped My Drive/ root without moving files:
uv run python download_google_doc.pyw --tenant default --plan-migrate-my-drive-rootReview JSON output:
uv run python download_google_doc.pyw --tenant default --plan-migrate-my-drive-root --migration-plan-format jsonApply only after reviewing a zero-collision plan:
uv run python download_google_doc.pyw --tenant default --apply-migrate-my-drive-rootThe apply command aborts before moving anything if the backup root is missing or any target path already exists.
The direct API path still uses local OAuth artifacts:
client_secrets.jsoncredentials.json
Keep real credentials out of version control. Regenerate credentials.json after permission changes, and prune stale tokens if authentication loops appear.
Run the narrow validation checks:
uv lock --check
uv run python -m py_compile download_google_doc.pyw
uv run python download_google_doc.pyw --tenant default --doctor
uv run python download_google_doc.pyw --tenant default --dry-run --show-configWhen adding logic, prefer focused offline pytest coverage under tests/ with fake Drive or backend responses.
On Windows consoles that default to cp1252, set PYTHONIOENCODING=utf-8 before launching the CLI so Unicode log messages do not trigger UnicodeEncodeError:
set PYTHONIOENCODING=utf-8 && python download_google_doc.pyw --backup "E:\Backups\Drive"