Skip to content

Add a Google Docs uploader (one doc per month) - #148

Merged
dbieber merged 2 commits into
mainfrom
claude/googledocs-uploader
Sep 9, 2026
Merged

Add a Google Docs uploader (one doc per month)#148
dbieber merged 2 commits into
mainfrom
claude/googledocs-uploader

Conversation

@dbieber

@dbieber dbieber commented Sep 9, 2026

Copy link
Copy Markdown
Owner

What

Adds a Google Docs note-taking backend (NOTE_TAKING_SYSTEM=googledocs) that appends notes to a Google Doc — no browser, no interactive OAuth.

Layout, one document per month:

September 2026                      ← the doc's title (one per month)

Monday, September 8th, 2026         ← day heading (Heading 1)
  6:30 AM                           ← session timestamp (Heading 2)
    • a note                        ← bulleted list, nested by indent level
    • another note
      • an indented note
  7:14 AM
    • a later session's note

How

  • googledocs_api.py — a small client for the Drive + Docs REST APIs. Auth is a Google service account (google-auth's AuthorizedSession). It finds the current month's doc by name or creates it (Drive files), optionally in a folder and shared with a configured email, then reads the doc and applies a batchUpdate. Scopes are documents + drive.file (the app only ever sees docs it created).
  • googledocs_uploader.py — turns note events into one insertText of the whole batch followed by paragraph-style and bullet requests. Notable details:
    • Day/session dedup across restarts: it re-reads the last Heading-1 in the doc, so a restart mid-day doesn't repeat the day heading.
    • Nesting via leading tabs + createParagraphBullets.
    • Request ordering high-index-to-low, so bullet creation (which consumes tabs and shifts following indices) never invalidates an earlier request's range in the same batch.
    • Returns False on any API error so notes stay queued.
  • Runner dispatch, settings template (GOOGLE_DOCS_CREDENTIALS, GOOGLE_DOCS_SHARE_EMAIL, GOOGLE_DOCS_FOLDER_ID, GOOGLE_DOCS_TITLE_FORMAT), settings-server UI, and the google-auth dependency.

Setup (for whoever configures a device)

  1. Create a Google Cloud service account; enable the Google Docs API and Google Drive API on its project; download its JSON key to the device (e.g. /home/pi/secrets/google_credentials.json).
  2. :set GOOGLE_DOCS_SHARE_EMAIL you@gmail.com so each month's doc is shared to you. (Optionally set GOOGLE_DOCS_FOLDER_ID.)
  3. :set NOTE_TAKING_SYSTEM googledocs.

Testing

  • 34 unit tests across the API client (fake HTTP session: query building, create+share, error handling) and the uploader (fake client: month-doc caching, day/session headings and their style ranges, tab nesting, no-duplicate-day-heading on restart, day rollover, empty-submit skipping, failure → False). Local run: full suite 99 passed, ruff clean.
  • Not yet exercised against the live Google API — that needs a real service account and is the natural next step when wiring up a device.

🤖 Generated with Claude Code

dbieber and others added 2 commits September 9, 2026 08:27
Uploads notes to Google Docs with no browser and no interactive OAuth, using a
Google service account. Keeps one document per month (found or created via the
Drive API and optionally shared with a configured email), and lays notes out as
day headings (Heading 1), per-session timestamp headings (Heading 2), and a
nested bulleted list that mirrors the indent levels typed.

- googledocs_api.py: Drive + Docs REST client (service-account auth, find/create/
  share month docs, get document, batchUpdate).
- googledocs_uploader.py: note-event -> structured Docs requests, with day/session
  dedup (re-learns the last day from the doc so restarts don't duplicate headings)
  and high-to-low request ordering so bullet creation never invalidates ranges.
- runner dispatch for NOTE_TAKING_SYSTEM='googledocs'; settings template, settings
  UI, and google-auth dependency.
- 34 unit tests (fake HTTP session / fake client), no network or Redis needed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…wn Drive)

A service account cannot own files in a consumer Gmail Drive, so add support for
authenticating as a Google user via a stored OAuth token (authorized_user JSON
with a refresh_token) in addition to service-account keys. load_credentials()
detects the kind by the JSON contents. Adds scripts/authorize_googledocs.py to
run the one-time consent flow and produce the token, and tests for the routing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@dbieber
dbieber merged commit b7ed2a5 into main Sep 9, 2026
1 of 2 checks passed
@dbieber
dbieber deleted the claude/googledocs-uploader branch September 9, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant