# Google Services Migration Plan — gws CLI Migrate from 15 custom Python scripts + 4 credential stores to a single [[gws]] CLI with unified auth. Planned 6 March 2026. ## Current State Three parallel systems accessing the same Google account: 1. 15 custom Python scripts (`~/.local/bin/google-*.py`) with OAuth token at `~/.config/google/token.json` — deeply wired into commands, skills, CLAUDE.md, CRITICAL-WORKFLOWS.md, morning review 2. gws CLI v0.7.0 (`/opt/homebrew/bin/gws`) with encrypted credentials at `~/.config/gws/credentials.enc` — installed, authenticated, 21 skills downloaded, but not integrated into any workflow 3. Claude.ai MCP connectors (Calendar + Gmail) — deferred tools, never used in workflows Plus a separate Google Contacts credential at `~/.config/google-contacts/`. ### Why migrate - One CLI, one auth, one credential store (currently four) - gws adds services we never had: Drive, Docs, Sheets, Slides, Keep - Token efficiency: CLI-via-Bash uses 4–35x fewer tokens than MCP (Anthropic engineering blog, Playwright benchmarks, Hacker News consensus — March 2026) - The old system had recurring auth pain (scope mismatches Jan 7–13, Python version issues Jan 20, all documented in `~/.claude/knowledge/google-services.md`) - gws handles API versioning automatically via Google Discovery Service — no maintenance when APIs change ### Why be cautious - gws is pre-v1.0 ("not an officially supported Google product") — breaking changes expected - The old system works and is battle-tested - google-tasks-sync.py has unique vault-writing behaviour that gws doesn't replicate - calendar-query.py supports natural language ("today", "this week") that gws needs explicit date params for ## Architecture Principle From `~/.claude/knowledge/system-design-practices.md`: "Data that must be fresh → API call via script, not cache file." The old tasks system violates this (sync to Google Tasks.md, then read the file). The migration is an opportunity to fix this — query tasks live via gws, like we already do for calendar and email. However, Google Tasks.md also serves as a mobile-accessible view in Obsidian. If we eliminate the sync, we lose that. Decision: keep a sync wrapper but build it on gws instead of the Python script. ## The Migration — Phased ### Phase 0: Verify gws parity (no changes, just testing) Test every operation that the old scripts perform, using gws directly in the terminal. Confirm output format, error handling, and auth stability. | Old script | gws equivalent | Test command | |---|---|---| | `google-calendar-query.py today` | `gws calendar +agenda` | `gws calendar +agenda` | | `google-calendar-query.py "meeting"` | `gws calendar events list --params '{"q":"meeting","timeMin":"...","timeMax":"..."}'` | manual | | `google-calendar-add.py "Title" "2026-03-07 14:00"` | `gws calendar +insert` (interactive helper) | `gws calendar +insert` | | `google-calendar-edit.py "Meeting" --title "New"` | `gws calendar events patch --params '{"calendarId":"primary","eventId":"..."}' --json '{"summary":"New"}'` | manual | | `google-calendar-delete.py "Meeting"` | `gws calendar events delete --params '{"calendarId":"primary","eventId":"..."}'` | manual | | `google-calendar-move.py "Event" "other_cal"` | `gws calendar events move --params '{"calendarId":"primary","eventId":"...","destination":"..."}'` | manual | | `google-tasks-sync.py` | `gws tasks tasks list --page-all` (needs formatting wrapper) | `gws tasks tasks list --params '{"tasklist":"@default"}'` | | `google-tasks-add.py "Task title"` | `gws tasks tasks insert --params '{"tasklist":"@default"}' --json '{"title":"Task title"}'` | manual | | `google-tasks-complete.py "query"` | `gws tasks tasks patch --params '{"tasklist":"@default","task":"ID"}' --json '{"status":"completed"}'` | manual | | `google-gmail-search.py "query"` | `gws gmail users messages list --params '{"userId":"me","q":"query"}'` | manual | | `google-gmail-read.py "ID"` | `gws gmail users messages get --params '{"userId":"me","id":"ID"}'` | manual | | `google-gmail-send.py` | `gws gmail +send` | `gws gmail +send` | Note: gws edit/delete/move operations require event IDs, not search queries. The old scripts did search-then-act internally. The new skills will need to handle this two-step pattern (search first, then act on results). ### Phase 1: Write bridge scripts Small shell scripts in `~/.local/bin/` that wrap gws commands to provide the same interface the old skills expect. This means existing skills can switch backends without changing their interface. Scripts needed: 1. `gws-tasks-sync.sh` — calls `gws tasks tasks list --page-all`, formats output as Markdown, writes to `Google Tasks.md`. Replaces `google-tasks-sync.py`. 2. `gws-calendar-query.sh` — accepts natural language args ("today", "tomorrow", "this week", keyword search), translates to gws date params, calls `gws calendar events list`. Replaces `google-calendar-query.py`. 3. `gws-gmail-search.sh` — accepts Gmail search query, calls `gws gmail users messages list`, formats output. Replaces `google-gmail-search.py`. 4. `gws-tasks-add.sh` — accepts task title + optional due date, calls `gws tasks tasks insert`. Replaces `google-tasks-add.py`. 5. `gws-calendar-add.sh` — accepts title + start time + optional end time/description/location/calendar, calls `gws calendar events insert`. Replaces `google-calendar-add.py`. These bridge scripts are the riskiest part. Each must exactly replicate the output format and error handling of the Python script it replaces. Test each one against its predecessor before proceeding. ### Phase 2: Update skills to use bridge scripts Change the old skills to call bridge scripts instead of Python scripts. This is a find-and-replace operation within each SKILL.md. Files to update: - `~/.claude/skills/google-calendar/SKILL.md` — change all `~/.local/bin/google-calendar-*.py` to `~/.local/bin/gws-calendar-*.sh` - `~/.claude/skills/google-calendar/add.md`, `edit.md`, `delete.md`, `move.md`, `query.md` — update script references - `~/.claude/skills/google-tasks/SKILL.md` — update script reference Alternatively (cleaner): retire the old skills entirely and update the gws-* skills to include the workflow instructions from the old skills. The gws skills currently just document the API surface; they'd need to gain the "how to use this in Nick's vault" layer. Decision point: update old skills or enhance gws skills? Enhancing gws skills is cleaner long-term but more work. Updating old skills is safer short-term. Recommendation: enhance gws skills. The old skills are wrappers around implementation details (specific Python scripts). The gws skills should become the new wrappers around the new implementation (gws CLI). This avoids a confusing state where "google-calendar" skill calls gws under the hood. ### Phase 3: Update commands Commands that need updating: | Command file | Current script | New approach | |---|---|---| | `~/.claude/commands/calendar-query.md` | `google-calendar-query.py` | `gws-calendar-query.sh` or inline gws | | `~/.claude/commands/calendar-add.md` | `google-calendar-add.py` | `gws-calendar-add.sh` or inline gws | | `~/.claude/commands/calendar-delete.md` | `google-calendar-delete.py` | inline gws | | `~/.claude/commands/calendar-move.md` | `google-calendar-move.py` | inline gws | | `~/.claude/commands/gmail-search.md` | `google-gmail-search.py` | `gws-gmail-search.sh` or inline gws | | `~/.claude/commands/google-tasks-sync.md` | `google-tasks-sync.py` | `gws-tasks-sync.sh` | | `~/.claude/commands/tasks-add.md` | `google-tasks-add.py` | `gws-tasks-add.sh` or inline gws | | `~/.claude/commands/tasks-complete.md` | `google-tasks-complete.py` | inline gws | | `~/.claude/commands/morning-review.md` | orchestrates calendar-query, tasks-sync, gmail-search | update to use new commands | | `~/.claude/commands/review.md` | references tasks, calendar, email | update | | `~/.claude/commands/system-check.md` | verifies Google scripts work | update verification targets | ### Phase 4: Update CLAUDE.md and CRITICAL-WORKFLOWS.md CLAUDE.md references: - "Tasks: Run google-tasks-sync first, then read Google Tasks.md" → update to gws workflow - Any references to specific Python scripts in behavioral requirements CRITICAL-WORKFLOWS.md references: - "Tasks: Required Sequence" section → update script references - "Calendar: Required Command" → update - "Email: Required Command" → update - Command chains table → update ### Phase 5: Update knowledge files - `~/.claude/knowledge/google-services.md` — rewrite to document gws architecture, new credential location, new script inventory - `~/.claude/knowledge/INDEX.md` — update the google-services entry description if needed ### Phase 6: Update settings.json permissions The `settings.json` has explicit Bash permissions for every old Python script. Add permissions for: - `gws` commands - New bridge scripts (`gws-*.sh`) Remove old permissions only after confirming everything works. ### Phase 7: End-to-end testing Run the following workflows and verify they work: - `/morning-review` (exercises calendar, tasks, email simultaneously) - `/tasks-add "Test task"` then `/tasks-complete "Test task"` - `/calendar-add "Test" "tomorrow 14:00"` then `/calendar-delete "Test"` - `/gmail-search "from:me"` - `/review` (quick status check) ### Phase 8: Deprecation (2 weeks later) After 2 weeks of the new system working: - Archive old Python scripts (move to `~/.local/bin/_deprecated/`) - Remove old permissions from settings.json - Delete `~/.config/google/token.json` and `~/.config/google/credentials.json` - Keep `~/.config/google-contacts/` (Contacts has no gws replacement) ## Complete Dependency Inventory Full audit of every file referencing old Google Python scripts, by architecture layer. 45 files total, ~20 requiring functional changes. ### High priority (functional — these break if scripts are removed) Settings (2 files): - `~/.claude/settings.json` — 34 allowlist entries for all Python scripts (both `~/.local/bin/script.py` and `python3` variants) - `~/.claude/settings.local.json` — project-local entries for google-tasks-sync, calendar-query, gmail-search, google-daily-fetch Commands (12 files): - `calendar-query.md`, `calendar-add.md`, `calendar-delete.md`, `calendar-move.md` — each wraps a calendar Python script - `gmail-search.md` — wraps google-gmail-search.py - `google-tasks-sync.md` — wraps google-tasks-sync.py - `tasks-add.md`, `tasks-complete.md` — wrap tasks scripts - `morning-review.md` — directly calls google-calendar-query.py, google-tasks-sync.py, google-gmail-search.py (lines 116–127) - `review.md` — directly calls all three sync scripts (lines 39–50) - `system-check.md` — integration tests calling old scripts, references `~/.config/google/token.json` - `system-status.md` — maps CLAUDE.md "tasks" rule to google-tasks-sync Skills (4 files): - `google-calendar/SKILL.md` — references all 5 calendar Python scripts - `google-tasks/SKILL.md` — references google-tasks-add.py - `google-tasks/add_task.py` — standalone Python script with its own separate `tasks-token.json` (!) - `readwise/SKILL.md` — uses google-gmail-send.py to email documents to Readwise (line 26) Utility script: - `session-reader.py` — lines 122–170 parse Bash commands for old script names to extract actions from session transcripts. Must be updated to recognise gws command patterns. ### Medium priority (policy/docs — causes confusion if stale) - `CLAUDE.md` — "Tasks: Run google-tasks-sync first, then read Google Tasks.md" (line 78); "Calendar: Always use calendar-query skill" (line 79) - `CRITICAL-WORKFLOWS.md` — Tasks/Calendar/Email required sequences (lines 118, 134, 148); command chains table (line 210) - `SYSTEM-ARCHITECTURE.md` — flow diagrams, quick reference (lines 73, 129, 133, 146, 222–226) - `~/.claude/knowledge/google-services.md` — entire file documents old architecture (needs full rewrite) - `~/.claude/knowledge/claude-architecture.md` — data freshness enforcement references (lines 98–100, 118–120) - `~/.claude/knowledge/config-sync.md` — references `~/.config/google/credentials.json` for new machine setup (line 115) ### Low priority (historical/informational) - `Notes/Google API Integration - Complete Failure Analysis.md` — historical docs (leave as-is) - `Notes/Vault Structure Guide.md` — references old command names (lines 159–165) - `Google Tasks.md` — frontmatter tag (keep) - `This Week.md` — references /calendar-query (line 13) - `compile_emails.sh` — calls google-gmail-read.py (update if still used) - Various daily notes — historical log entries (leave as-is) - `skill-eval-hook.sh.disabled` — references old skill names (update if re-enabled) - 4 `.tmp_session*.txt` files — delete (temporary) ## What NOT to migrate - Google Contacts scripts (`google-contacts-fetch.py`, `gmail-search-contacts.py`) — gws doesn't cover People API. Keep as-is with separate auth. - The Claude.ai MCP connectors — they're passive (deferred tools) and cost nothing when unused. No action needed. ## Risks 1. gws is pre-v1.0. A breaking change could disrupt workflows. Mitigation: pin the version (`npm install -g @googleworkspace/[email protected]`), don't auto-update. 2. gws auth token expiry behaviour is unknown (how does refresh work? does it re-prompt?). The old system had painful token refresh issues. Test this explicitly. 3. The bridge scripts are new code that could have bugs. Test each one thoroughly before wiring into workflows. 4. Morning review is the highest-stakes workflow (runs daily, first thing). It should be the last thing migrated, not the first. ## Execution order (what to do first) 1. Phase 0 testing (today — just run gws commands manually, zero risk) 2. Phase 1 bridge scripts (write and test independently) 3. Phase 2+3 together (update skills and commands to use bridge scripts) 4. Phase 7 testing (verify everything works) 5. Phase 4+5+6 (update docs and config — only after workflows confirmed working) 6. Phase 8 cleanup (2 weeks later) Total estimated effort: 2–3 sessions for phases 1–4, one session for phase 5–6, then wait 2 weeks for phase 8.