app
Adom Google
Public Made by Adomby adom
Drive your whole Google Workspace from the terminal, run by your AI. Read Gmail, write Google Docs, build Google Sheets and Google Slides, search Google Drive, manage Google Calendar and Google Tasks, and post to Google Chat, plus any Google API and a zero-setup personal Gmail.
← Commit history
Set page tags + restructure for adompkg (skills/ layout, link-bin install); v0.4.0
5 files changed
+258−19
install.sh+29−10@@ -1,10 +1,29 @@-#!/bin/bash-# adompkg install hook: put adom-google on PATH + drop its skill in place.-set -e-DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"-mkdir -p "$HOME/.local/bin" "$HOME/.claude/skills/adom-google"-chmod +x "$DIR/bin/adom-google" "$DIR/bin/adom-gmail"-ln -sf "$DIR/bin/adom-google" "$HOME/.local/bin/adom-google"-ln -sf "$DIR/bin/adom-gmail" "$HOME/.local/bin/adom-gmail"-cp -f "$DIR/SKILL.md" "$HOME/.claude/skills/adom-google/SKILL.md"-echo "✅ adom-google installed. Next: run 'adom-google setup' (it will ask safe vs full mode)."+#!/usr/bin/env bash+# adom-google installer — the open-source Google Workspace CLI. Runs in the container via+# `adompkg install`. Ships with NO OAuth provider: the binary + skill are symlinked onto PATH+# via the adompkg sh-helpers (lint-sanctioned convention). Configure a provider after install+# (`adom-google provider set ...`) — or, Adom staff, install the private `adom-google-adom`.+set -euo pipefail+HERE="$(cd "$(dirname "$0")" && pwd)"+cd "$HERE"++if ! command -v adompkg >/dev/null 2>&1; then+ echo "[adom-google] FATAL: adompkg not on PATH — install via 'adompkg install adom-google'." >&2+ exit 1+fi+# shellcheck disable=SC1090+source "$(adompkg sh-helpers)"++chmod +x bin/adom-google bin/adom-gmail+adompkg-link-bin adom-google # ~/.local/bin/adom-google -> $PWD/bin/adom-google+adompkg-link-bin adom-gmail # deprecation shim -> adom-google+adompkg-link-skill adom-google # ~/.claude/skills/adom-google -> $PWD/skills/adom-google++case ":$PATH:" in+ *":$HOME/.local/bin:"*) ;;+ *) echo "[adom-google] NOTE: $HOME/.local/bin is not on PATH — add it to your shell rc." ;;+esac+echo "✅ adom-google installed. It ships with NO OAuth provider — set one up:"+echo " • self-host: adom-google provider set --gateway https://your-gateway --client-id <id>"+echo " • Adom staff: adompkg install adom-google-adom (drops the Adom provider)"+echo " Then: 'adom-google setup' (asks safe vs full) and 'adom-google auth'."
package.json+39−4@@ -1,8 +1,28 @@ { "slug": "adom-google",- "version": "0.3.0",+ "version": "0.4.0", "type": "app",- "description": "Drive your whole Google Workspace from the terminal \u2014 Gmail, Contacts, Drive, Sheets, Docs, Slides, Calendar, Tasks, Google Chat, plus a generic `api` passthrough to hit ANY Google API. Open source, ships with NO OAuth provider baked in: point it at your own token-broker gateway (`provider set`), buy a managed one, or \u2014 Adom staff \u2014 install the private adom-google-adom provider. One-click OAuth, no client secret on your machine. First run asks safe mode (no delete) vs full mode (incl. delete).",+ "description": "Drive your whole Google Workspace from the terminal — Gmail, Contacts, Drive, Sheets, Docs, Slides, Calendar, Tasks, Google Chat, plus a generic `api` passthrough to hit ANY Google API. Open source, ships with NO OAuth provider baked in: point it at your own token-broker gateway (`provider set`), buy a managed one, or — Adom staff — install the private adom-google-adom provider. One-click OAuth, no client secret on your machine. First run asks safe mode (no delete) vs full mode (incl. delete).",+ "keywords": [+ "adom-google",+ "google-workspace",+ "oauth",+ "gmail",+ "google-sheets",+ "google-docs",+ "google-slides",+ "google-calendar",+ "google-chat",+ "cli",+ "ai-agent"+ ],+ "tags": [+ "google-workspace",+ "oauth",+ "gmail",+ "cli",+ "ai-agent"+ ], "install": { "binary_name": "adom-google" },@@ -10,5 +30,20 @@ "scripts": { "install": "./install.sh", "uninstall": "./uninstall.sh"- }-}+ },+ "files": [+ "bin/adom-google",+ "bin/adom-gmail",+ "skills/adom-google/SKILL.md",+ "README.md",+ "MIGRATION.md",+ "provider.example.json",+ "docs/hero.png",+ "docs/enable-apis.png",+ "docs/chat-reads-email.png",+ "screenshots/hero.png",+ "install.sh",+ "uninstall.sh",+ "package.json"+ ]+}
page.json+8−2@@ -4,7 +4,7 @@ "slug": "adom-google", "title": "adom-google", "brief": "Drive your whole Google Workspace from the terminal \u2014 Gmail, Drive, Sheets, Docs, Slides, Calendar, Tasks, Chat + any Google API.",- "version": "0.3.0",+ "version": "0.4.0", "visibility": "public", "install": { "binary_name": "adom-google",@@ -17,7 +17,13 @@ "name": "John Lauer", "email": "[email protected]" },- "tags": [],+ "tags": [+ "google-workspace",+ "oauth",+ "gmail",+ "cli",+ "ai-agent"+ ], "license": "Apache-2.0", "hero": { "path": "docs/hero.png",
skills/adom-google/SKILL.mdadded+178@@ -0,0 +1,178 @@+---+name: adom-google+description: Programmatic read+write access to a user's WHOLE Google Workspace — Gmail, Contacts, Drive, Sheets, Docs, Slides, Calendar, Tasks, Google Chat — plus a generic `api` passthrough to hit ANY Google API. CLI + OAuth only (no browser automation). Public/open-source; used daily by the Adom team. Auth is the account-specific part: Adom employees use it out of the box; other orgs either self-host their own OAuth gateway or email [email protected] for a managed OAuth container (~$5/mo). On FIRST-RUN SETUP you MUST ask the user to pick safe mode (no delete) vs full mode (incl. delete) before authorizing. Use when setting up/installing adom-google, authorizing Google, reading Gmail attachments/.ics, creating/listing/searching Contacts, editing Sheets/Docs/Slides, Drive files, Calendar events, posting to Google Chat, or any Google Workspace automation. Trigger words — adom-google, install adom-google, set up adom-google, configure adom-google, google workspace cli, edit google sheet/doc/slides, drive upload, calendar event, post to google chat, gmail attachment, google contacts, people api, safe mode vs full mode, google oauth gateway broker, google api passthrough, self-host oauth, managed oauth container.+---++# adom-google++One CLI for a user's Google Workspace from inside an Adom container. **REST-direct** —+it calls the Google APIs straight, owns auth via the **Adom OAuth Gateway**, and stores a+long-lived refresh token `0600`. No browser automation, no per-user Google Cloud project.++```+adom OAuth layer one shared Adom OAuth client + Gateway redirect → refresh token (0600)+adom-google modular wrapper: gmail · contacts · (drive/calendar = +1 scope line)+Google REST APIs called directly (gmail.googleapis.com, people.googleapis.com, …)+```++## Why REST-direct (not a base-CLI shim)++We evaluated wrapping a base CLI — Google's `googleworkspace/cli` (`gws`, Rust,+Discovery-driven, JSON, agent skills), `gog`/`gogcli` (Go), GAM/GAMADV-XTD3, the+Gemini CLI, and `gcloud`. Conclusion: **call the REST APIs directly.**++- **Auth is the part Adom must own anyway.** One shared internal OAuth client + the+ Gateway's static redirect + a long-lived refresh token is Adom-specific; no base CLI+ speaks it. Adopting one means reverse-engineering its keyring/credential format to+ inject our token — more work than one `requests.post` to the token endpoint.+- **The data surface we need is tiny and stable.** gmail.readonly attachment reads + a+ handful of People API calls. Each is one HTTPS request. A base CLI adds a process+ boundary, an install/version dependency, and output coupling for no benefit at this size.+- **No per-user GCP project.** REST-direct with the shared Adom client satisfies the hard+ constraint. `gws`/`gog`/GAM all push users toward their own OAuth client or `gcloud`.+- **Gemini CLI is the wrong layer** (an AI coding agent, not a Workspace data client) and+ **gcloud can't touch Workspace user data** (GCP-only). `gws` is the closest "official"+ Google Workspace CLI and is a reasonable **future accelerator** if we ever need broad+ Sheets/Docs/Chat coverage — but for Gmail+Contacts it's overkill.++The code is structured so a `gws` backend *could* be slotted behind the same subcommands+later; today the win is zero new runtime dependencies and a clean migration from adom-gmail.++## Install++`install.mjs` symlinks the CLI onto PATH automatically. Manual:++```bash+ln -sf <gallia>/skills/adom-google/bin/adom-google ~/.local/bin/adom-google+ln -sf <gallia>/skills/adom-google/bin/adom-gmail ~/.local/bin/adom-gmail # deprecation shim+```++Runtime: Python 3 + `requests` (already in the container). The Gateway WebSocket handshake+is implemented in the stdlib (no `ws`/`websockets` package).++## First-run setup — YOU MUST ASK THE USER which mode (REQUIRED)++When setting up adom-google on a user's container for the first time (it's unconfigured —+`adom-google setup` or any command prints a `Hint:` block saying so), **do NOT pick a mode+for them. Ask.** Use `AskUserQuestion` with these two options:++- **Safe mode (recommended default)** — read/organize Gmail, full Contacts, Calendar events,+ Tasks, post+read Google Chat, and only the Drive/Sheets/Docs/Slides files *this app+ creates*. Scopes: `gmail.modify, contacts, calendar.events, tasks, chat.messages,+ chat.spaces.readonly, drive.file`. The Google consent screen shows **no "see & delete ALL+ your files"** — nothing scary.+- **Full mode** — everything safe mode has, but the narrow Drive/Sheets/Docs/Slides/Calendar+ scopes are swapped for broad read/write/**delete** across **all** the user's existing+ files and calendars. Scopes add `drive, spreadsheets, documents, presentations, calendar`.+ Only if they explicitly want full control.++Both modes also expose the generic `adom-google api <url>` passthrough, which can hit **any**+Google API the granted scopes allow (Sheets/Docs/Slides/Drive/Calendar/Chat/Tasks/YouTube/…).++Then run exactly one:+```bash+adom-google auth # safe mode (user picked safe)+adom-google auth --full # full mode (user picked full — includes delete)+```+The CLI emits this same instruction as `Hint:` lines whenever it's unconfigured, so you'll+be reminded at the exact moment of need even if this skill has been compacted out of context.++## Auth — one consent, long-lived refresh token++```bash+adom-google auth # SAFE mode (default): no "delete all" on the consent screen+adom-google auth --full # FULL mode: broad access incl. delete (trusted users)+adom-google auth --manual # fallback: desktop-client paste flow (combine with --full)+adom-google auth-code '<code>' # finish --manual+adom-google status # shows mode + what's authorised (never prints secrets)+```++### How Adom handles the OAuth (Gateway broker flow)++Google requires one fixed `redirect_uri`, but every container has a unique hostname. The+Adom OAuth Gateway gives one static callback for all containers **and** acts as a+confidential-client **token broker**, so the client secret never reaches user containers:++1. `adom-google auth` builds the Google consent URL with+ `redirect_uri = <your gateway>/callback` (from the resolved provider) and a random `state`,+ and opens a WebSocket to the Gateway registering `{state, app:"adom-google", exchange:true}`.+2. The user approves in their browser (their own Google Workspace account).+3. Google redirects to the Gateway `/callback`; the Gateway **does the code→token exchange+ itself** (using the secret it alone holds) and pushes `{type:"tokens", …}` over the WS.+4. The container stores only the **refresh token** `0600` — no client secret. Later refreshes+ go through the gateway's `POST /refresh`, so the secret stays on the gateway forever.++**The package ships NO provider** — no gateway URL, no client_id, nothing Adom-specific. The+provider (`{gateway_url, client_id, app}`) is resolved at runtime, later wins: bundled+`provider.json` → legacy `credentials.json` → `~/.config/adom-google/provider.json` → env+(`OAUTH_GATEWAY_URL`, `ADOM_GOOGLE_CLIENT_ID/SECRET/APP`). With none configured, every command+prints the NO_PROVIDER hint. Adom employees install the private **`adom-google-adom`** package,+which writes the Adom provider (gateway + Internal client_id) to `~/.config/adom-google/provider.json`;+self-hosters run `adom-google provider set --gateway <url> --client-id <id>`. The client secret is+never in any package — in broker mode it lives only on the gateway's `creds/<app>.json` (0600).++If the Gateway is down, `auth --manual` uses a desktop-client loopback paste flow (that one+exchanges locally and does need a client secret via `init`).++### Getting auth as a NON-Adom user (this tool is public)++The code is open source; the OAuth app + gateway are account-specific. If a user is **not**+on Adom's Workspace, the bundled Internal client won't let them sign in — Google blocks+non-adom.inc accounts at consent. Two options to surface to them:++1. **Managed by Adom (easiest):** email **[email protected]** — Adom stands up a dedicated+ OAuth gateway container for their org (~$5/mo) wired to a Google client for their domain;+ they then get the full adom-google capability set, same as the Adom team.+2. **Self-host (DIY):** fork the repo; create their own Google Cloud project + OAuth client+ (Internal to their Workspace), enable the APIs they need, run the open-source OAuth gateway+ (`john/service-oauth`) with their client secret in `creds/<app>.json`, then point the CLI at+ theirs: `adom-google provider set --gateway https://their-gateway --client-id <their-id>`+ (writes `~/.config/adom-google/provider.json`). Google **Chat** also needs a one-time+ Chat-app configuration (name/avatar/description) in the Cloud console's Chat API →+ Configuration tab, or `spaces.*` calls 404 with "Chat app not found".++## Commands++```bash+# Generic passthrough — ANY Google API, signed with the user's token. This is the workhorse:+# Sheets/Docs/Slides/Drive/Calendar/Chat/Tasks/YouTube all go through here, zero per-API code.+adom-google api <url> [-X METHOD] [-d '<json>'|@file] [-q key=val ...] [--raw]+# e.g. create a sheet: adom-google api -X POST https://sheets.googleapis.com/v4/spreadsheets -d '{"properties":{"title":"BOM"}}'+# post to Chat: adom-google api -X POST https://chat.googleapis.com/v1/spaces/<id>/messages -d '{"text":"shipped"}'+# calendar event: adom-google api -X POST https://www.googleapis.com/calendar/v3/calendars/primary/events?sendUpdates=all -d '{...}'++# Gmail (read; behaviour-compatible with old adom-gmail)+adom-google gmail attachments <messageId>+adom-google gmail read <messageId> <attachmentId> [-o file]+adom-google gmail ics <messageId>++# Contacts (People API; read + write)+adom-google contacts create --name "First Last" [--org O] [--title T] \+ [--email [email protected] ...] [--phone +1... ...] [--notes "..."] [--json]+adom-google contacts list [--limit N] [--json]+adom-google contacts search <query> [-v] [--json]++adom-google status # mode (safe/full) + what's authorized (never prints secrets)+```++We use Google Contacts to store **service identities** (portal/account metadata for an API+vendor), e.g. the JPMorgan Payments developer portal. Keep secrets (client secrets, portal+passwords) in a password manager — **never** in a contact's notes.++## Adding Drive / Calendar++Add the scope to `SCOPES` at the top of `bin/adom-google`, re-run `adom-google auth`, and+add a few REST calls against `www.googleapis.com/drive/v3` or `/calendar/v3`. Token refresh+and the `_request()` helper are already generic.++## Security++- Config `~/.config/adom-google/config.json` is created `0600`; the client secret and+ refresh token are never echoed to stdout/stderr or logs (`status` prints presence only).+- The Gateway only ever sees the short-lived auth `code`, never tokens or the client secret.++## Migration from adom-gmail++See [MIGRATION.md](MIGRATION.md). Short version: `adom-gmail` is now a forwarding shim;+its old `~/.config/adom-gmail/config.json` is auto-imported on first `adom-google` run+(gmail.readonly only — run `adom-google auth` once to add the `contacts` scope).
uninstall.sh+4−3@@ -1,4 +1,5 @@-#!/bin/bash+#!/usr/bin/env bash+set -euo pipefail rm -f "$HOME/.local/bin/adom-google" "$HOME/.local/bin/adom-gmail"-rm -rf "$HOME/.claude/skills/adom-google"-echo "adom-google uninstalled (your ~/.config/adom-google token is left intact)."+rm -f "$HOME/.claude/skills/adom-google" # remove the skill symlink+echo "adom-google uninstalled (your ~/.config/adom-google token + provider are left intact)."