Pure Phoenix Phase 4.6, Drive Subsystem Redesign (forge side)¶
Forge-side CLI for Google Drive ships. n8n workflows are scaffolded; pure-API path is live and FUSE mount is now optional for forge scripts.
Plan: ~/.claude/plans/yes-lets-go-into-pure-phoenix.md Section 4.6.
Doctrine: FORGE-DOCTRINE.md.
Inventory: pure-phoenix-inventory-2026-04-28.
What ships¶
CLI (5 scripts)¶
All under forge/scripts/, doctrine-compliant flat-named, snake_case.
| Script | Operation | Reuses |
|---|---|---|
forge_gdrive_search.py |
list/grep Drive paths, JSON output | rclone lsjson |
forge_gdrive_read.py |
stream/download a Drive file (path or ID), optional Google-Doc export-as conversion | rclone cat/copyto |
forge_gdrive_write.py |
upload from local file or stdin, optional convert-to-Google-Doc on import | rclone copyto |
forge_gdrive_move.py |
rename or relocate inside Drive, optional rmdir | rclone moveto/rmdir |
forge_gdrive_index_extend.py |
mirror Drive subtrees into forge/data/gdrive-cache/ as extracted markdown for /recall |
rclone copyto + pandoc |
All five run without depending on the FUSE mount. They talk to the Drive API through Justin's existing gdrive: rclone remote (full drive OAuth scope, refresh token, no new credentials needed).
/recall index extension¶
forge/scripts/forge_search_index.py ROOTS now includes forge/data/gdrive-cache/. Run forge_gdrive_index_extend.py [--in subtree] [--rebuild-index] to mirror Drive content as markdown into the cache, then re-embed. Default subtrees: Inbox, Business/Notes, Personal/Notes. Cap is 500 files per subtree per run.
Pandoc handles .docx to markdown and .pdf to plain text. Native Google Docs/Sheets/Slides convert via rclone's --drive-export-formats chain (md > html > txt for Docs).
n8n workflows¶
infra/n8n/workflows/gdrive-search.json shipped as scaffold using Execute Command + SSH-to-Console pattern. The other workflows (read, write, move, create-folder) follow the same shape; documented in infra/n8n/workflows/README-gdrive-phase-4-6.md. Justin's call whether to clone the scaffold or use n8n's native Google Drive node.
What's NOT done (deferred)¶
| Item | Why | When |
|---|---|---|
Brain tool surface (gdrive_read, gdrive_write, gdrive_search, gdrive_move) |
inbox + lifeos brains are themselves being redone in Phase 4.2 | wire during Phase 4.2 bot redesign |
| Read/write/move n8n workflows beyond the scaffold | needs Justin's call on SSH vs native Google Drive node | after he picks |
Drive share operation |
rclone alone cannot share to a specific email; needs google-api-python-client | Phase 4.6b if needed |
| 7-day parallel soak with FUSE mount | live now, soak window starts here | retire mount-watchdog cron after 2026-05-05 |
| LESSONS.md mount-watchdog doctrine-violation closure | gated on the 7-day soak | 2026-05-05 |
Mount-watchdog status¶
Per CP-4 in the master plan, the FUSE mount + mount-watchdog cron stay alive through the soak. After 2026-05-05, if no script that anyone cares about still requires the mount, retire the cron entry and close the LESSONS.md violation entry.
The forge_gdrive_*.py scripts and the /recall extender are already mount-independent. The remaining mount-dependent surfaces are:
- /save-to-drive skill (still uses cp /tmp/x.docx /mnt/workspace/Google-Drive/)
- Any human file-browser usage (you opening Files.app on the mount)
- Legacy scripts that haven't been moved over
The /save-to-drive skill should be migrated to call forge_gdrive_write.py directly. That's the last forge-script user of the mount. Do that and the mount becomes purely a human convenience.
Architecture¶
Justin
|
writes/reads files
|
+----------v-----------+
| Google Drive API |
+----------^-----------+
|
+--------------+--------------+
| |
rclone (forge_gdrive_*.py) n8n native Drive node
| |
forge scripts workflows
|
+-------v--------+
| /recall index |
| (gdrive-cache) |
+----------------+
The FUSE mount sits parallel as a human-convenience layer; it is no longer in the critical path for forge automation.
Verification done in this session¶
forge_gdrive_search.py --in / --max 5returned 5 .docx records from Drive root.forge_gdrive_write.py /tmp/p46_smoke.txt Inbox/p46_smoke.txt --mkdir-parentsuploaded successfully.forge_gdrive_move.py Inbox/p46_smoke.txt Inbox/p46_smoke_renamed.txtrenamed.forge_gdrive_read.py "2026-03-25_Water-Softener-Info.docx" --out /tmp/water2.docxdownloaded the real .docx (6776 bytes).forge_gdrive_index_extend.py --in "" --max 5extracted 5 .docx files via pandoc intoforge/data/gdrive-cache/as markdown. Cache opens as readable text.- Test artifact in Drive cleaned up via
rclone delete.
Known sharp edges¶
--drive-export-formatsflag is poison for non-native binary files. rclone interprets it as "this should be a Google Doc, look for the export"; if the file is already a real .docx, lookup fails with "directory not found". The scripts only pass the flag when--asis explicitly used on the CLI.- rclone OAuth token refreshes automatically. Token at
~/.config/rclone/rclone.confhas the refresh token; rclone refreshes the access token transparently when it expires. No script changes needed if expiry hits mid-call. - Cache de-dup uses mtime comparison. Drive's modified timestamp is parsed and compared against the cache file's mtime. If Drive's clock skews ahead, you'll re-extract every run. If you suspect this, run with
--pruneto also drop stale entries. - Pandoc 3.1.3 is installed. Both
.docx -> mdand.pdf -> plainwork. PDF extraction quality varies with the source PDF.
Manual actions Justin owns¶
| Action | When |
|---|---|
| Decide n8n integration path (SSH vs native) and either import + clone the scaffold or build via Drive node | when he wants Drive operations from n8n |
Migrate /save-to-drive skill to call forge_gdrive_write.py |
next time he touches the skill or before retiring mount-watchdog |
Add 0 5 * * * forge_gdrive_index_extend.py --rebuild-index to crontab if he wants nightly Drive indexing |
after he reviews the cache size for his usage pattern |
| Retire mount-watchdog cron + close LESSONS.md violation entry | after 2026-05-05 soak completes |
Files created / modified¶
| Path | Action |
|---|---|
forge/scripts/forge_gdrive_search.py |
created |
forge/scripts/forge_gdrive_read.py |
created |
forge/scripts/forge_gdrive_write.py |
created |
forge/scripts/forge_gdrive_move.py |
created |
forge/scripts/forge_gdrive_index_extend.py |
created |
forge/scripts/forge_search_index.py |
added data/gdrive-cache to ROOTS |
forge/infra/n8n/workflows/gdrive-search.json |
scaffold |
forge/infra/n8n/workflows/README-gdrive-phase-4-6.md |
created |
forge/data/gdrive-cache/ |
created (5 sample files mirrored from Drive root for verification) |
forge/logs/gdrive-index.log |
created |
~/.claude/projects/-home-justinwieb-forge/memory/reference_gdrive_subsystem.md |
created (this handoff's topic file) |
~/.claude/projects/-home-justinwieb-forge/memory/MEMORY.md |
added gdrive subsystem pointer |
forge/memory/handoffs/pure-phoenix-inventory-2026-04-28.md |
Phase 4.6 entry appended |
forge/LESSONS.md |
Phase 4.6 closeout entry appended |
[Claude Code, Pure Phoenix Phase 4.6]