Skip to content

Drive Subsystem, Pure Phoenix Phase 4.6

Doctrine: FORGE-DOCTRINE.md Section 14A. Handoff: pure-phoenix-phase-4-6-drive-redesign-2026-04-28.

Why this exists

The FUSE mount at /mnt/workspace/Google-Drive/ had recurring "transport endpoint not connected" zombies that broke /save-to-drive, n8n triggers, and any script that touched it. Phase 4.6 builds an API-direct path that bypasses FUSE entirely.

What's where

Path Role
forge/scripts/forge_gdrive_search.py List/find files by path/name/ext, JSON output
forge/scripts/forge_gdrive_read.py Download a file (path or Drive ID), optional native Google Doc export-as
forge/scripts/forge_gdrive_write.py Upload a local file or stdin content, optional convert to Google Doc
forge/scripts/forge_gdrive_move.py Rename or relocate, supports rmdir
forge/scripts/forge_gdrive_index_extend.py Mirror Drive subtrees as markdown into forge/data/gdrive-cache/
forge/scripts/forge_search_index.py Extended ROOTS to include the gdrive-cache for /recall coverage
forge/infra/n8n/workflows/gdrive-search.json n8n scaffold using SSH + Execute Command pattern
forge/infra/n8n/workflows/README-gdrive-phase-4-6.md n8n integration playbook
forge/data/gdrive-cache/ Cache of extracted Drive content for /recall
forge/logs/gdrive-index.log Index extender log

Auth model

All scripts use Justin's existing gdrive: rclone remote. No service account, no new credentials. The rclone config at ~/.config/rclone/rclone.conf holds the OAuth refresh token; rclone handles the access-token refresh transparently. Scope is full drive (read + write + share).

Examples

# search
forge_gdrive_search.py --in "Inbox" --ext docx --max 20
forge_gdrive_search.py --id 1xY...                          # by Drive ID
forge_gdrive_search.py --in "Business" --recursive --files-only

# read
forge_gdrive_read.py "Inbox/foo.md"                         # cat to stdout
forge_gdrive_read.py "Inbox/foo.docx" --out /tmp/foo.docx   # save local
forge_gdrive_read.py "MyDoc" --as md                        # native Google Doc export to markdown

# write
forge_gdrive_write.py /tmp/note.md "Inbox/note.md" --mkdir-parents
echo "quick note" | forge_gdrive_write.py --stdin --as-name "quicknote.md" "Inbox" --mkdir-parents

# move/rename
forge_gdrive_move.py "Inbox/note.md" "Personal/Notes/note.md" --mkdir-parents
forge_gdrive_move.py --rmdir "Inbox/empty-folder"

# extend /recall index
forge_gdrive_index_extend.py --in "Inbox" --in "Business/Notes" --max 200 --prune --rebuild-index

Safety properties

  • Mount-independent. Works whether the FUSE mount is alive, dead, or absent.
  • Read-only by default. Search and read are non-destructive. Write/move/rmdir change Drive state, run with care.
  • No auto-share. No script grants new permissions; sharing requires manual user-level action.

Sharp edges (logged in handoff)

  1. --drive-export-formats only goes on real native Google Docs (the script omits it unless --as was passed).
  2. The mtime-based cache invalidation can re-extract on Drive clock skew; pass --prune to clean.
  3. SSH path for n8n requires the n8n LXC's SSH key to be authorized on Console.

Outstanding work (handed off to Justin)

  • Migrate /save-to-drive skill to call forge_gdrive_write.py (last forge-script user of FUSE mount)
  • Decide n8n integration path; either clone scaffold for read/write/move or use native Drive node
  • Schedule forge_gdrive_index_extend.py --rebuild-index nightly if he wants persistent Drive /recall coverage
  • After 2026-05-05 soak, retire mount-watchdog cron and close the LESSONS.md violation entry

[Claude Code, Pure Phoenix Phase 4.6]