Google Readonly CLI is a read-only command-line interface for interacting with Google services, designed to provide secure, non-destructive access to Gmail, Google Calendar, Google Contacts, and Google Drive. It allows users to search messages, view email content, manage calendar events, organize contacts, and browse files in Drive without the ability to send, delete, or trash data.
Key Features:
Non-Destructive Access: Enables read-only operations with organizational capabilities like archiving, starring, labeling, categorizing, and RSVPing.
Gmail Support: Includes features such as searching messages, viewing threads, listing labels, downloading attachments, and performing actions like marking emails as read/unread or applying categories.
Calendar Management: Allows users to list calendars, view events, filter by date ranges, and manage event details with color-coding and RSVP functionality.
Contacts Organization: Supports listing contacts, searching, viewing contact details, managing groups, starring contacts, and organizing contacts into groups.
Drive Access: Enables browsing files, searching for content, viewing metadata, downloading files, exploring folder trees, and managing stars on Drive items.
Secure OAuth Storage: Stores tokens securely in the system keychain (macOS/Linux) to ensure safe credential management.
JSON Output: Provides machine-readable output for scripting and integration purposes.
Bulk Operations: Supports pipelining IDs between commands, using search queries inline, or passing IDs as arguments for efficient batch processing.
Audience & Benefit:
Ideal for developers, system administrators, and automation enthusiasts who need to integrate Google services into their workflows without the risk of data loss. The tool allows users to enhance productivity by leveraging command-line efficiency while ensuring secure access to Google services. It is particularly beneficial for those looking to script or automate tasks involving Gmail, Calendar, Contacts, and Drive without compromising data integrity.
The software can be installed via winget, making it accessible through a simple command-line installation process.
README
google-readonly
A non-destructive command-line interface for Google services. Search, read, and organize Gmail messages, calendar events, contacts, and Drive files. Supports labeling, archiving, starring, RSVP, and group management. No send, delete, or trash operations are possible.
Features
Non-destructive by design - Read access plus organizational operations; no send, delete, or trash
Gmail support - Search messages, read content, view threads, list labels, download attachments, archive, star, label, categorize, mark read/unread
Calendar support - List calendars, view events, today/week shortcuts, RSVP, color-coding
Contacts support - List contacts, search, view details, list groups, star, group management
Drive support - List files, search, view metadata, download files, folder tree, star/unstar
Bulk operations - Pipe IDs between commands, use search queries inline, or pass IDs as arguments
JSON output - Machine-readable output for scripting
Secure storage - OAuth tokens stored in system keychain (macOS/Linux)
> Note on scopes: gro uses the gmail.modify scope (a superset of gmail.readonly) because organizational operations like archive, label, and star require it. Similarly, contacts and calendar.events scopes enable starring, group management, and RSVP. No send, delete, or trash operations are possible regardless of scope.
3. Publish Your OAuth App (Recommended)
By default, new OAuth apps are in "Testing" mode, which causes tokens to expire after 7 days. To avoid frequent re-authentication:
Go to Google Auth Platform > Audience (or OAuth consent screen in older UI)
Find the Publishing status section
Click Publish app
For personal use with these scopes, publishing is straightforward and doesn't require Google verification. Once published, tokens will last until revoked or unused for 6 months.
> Note: If you skip this step, you'll need to run gro init every 7 days to re-authenticate.
Your browser will redirect to a localhost URL (the error page is expected)
Copy the entire URL or just the authorization code
Paste it back into the terminal
Your token will be saved securely (system keychain on macOS/Linux, or ~/.config/google-readonly/token.json as fallback).
Commands
Configuration Commands
# Guided OAuth setup
gro init
# Check configuration status
gro config show
# Test API connectivity
gro config test
# Clear stored OAuth token
gro config clear
# View cache status
gro config cache show
# Clear cached data
gro config cache clear
# Set cache TTL (in hours)
gro config cache ttl 12
# Show version
gro --version
Gmail Commands
All Gmail commands are under gro mail:
# Search messages
gro mail search "is:unread"
gro mail search "from:someone@example.com" --max 20
gro mail search "subject:meeting" --json
gro mail search "is:starred" --ids # Output IDs only (for piping)
# Read a message
gro mail read
gro mail read --json
# View conversation thread
gro mail thread
gro mail thread --json
# List labels
gro mail labels
gro mail labels --json
# List attachments
gro mail attachments list
gro mail attachments list --json
# Download attachments
gro mail attachments download --all
gro mail attachments download --filename report.pdf
gro mail attachments download --all --output ~/Downloads
gro mail attachments download --filename archive.zip --extract
# Archive messages (remove from inbox)
gro mail archive
gro mail archive --query "from:noreply older_than:30d"
gro mail search "from:noreply" --ids | gro mail archive --stdin
# Star / unstar messages
gro mail star
gro mail unstar
# Mark read / unread
gro mail mark-read
gro mail mark-unread
# Add / remove labels
gro mail label "Work"
gro mail unlabel "Promotions"
# Recategorize messages
gro mail categorize promotions
Calendar Commands
All Calendar commands are under gro calendar (or gro cal):
# List all calendars
gro calendar list
gro cal list --json
# List upcoming events
gro calendar events
gro cal events --max 20
gro cal events --from 2026-01-01 --to 2026-01-31
# Get event details
gro calendar get
gro cal get --json
# Today's events
gro calendar today
gro cal today --json
# This week's events
gro calendar week
gro cal week --json
# RSVP to an event
gro calendar rsvp accept
gro cal rsvp decline
gro cal rsvp tentative
# Set event color
gro calendar color tomato
gro cal color lavender
Contacts Commands
All Contacts commands are under gro contacts (or gro ppl):
# List all contacts
gro contacts list
gro ppl list --max 20
gro contacts list --json
gro contacts list --ids # Output resource names only
# Search contacts
gro contacts search "John"
gro ppl search "example.com" --max 20
gro contacts search "John" --ids # Output resource names only
# Get contact details
gro contacts get people/c123456789
gro ppl get people/c123456789 --json
# List contact groups
gro contacts groups
gro ppl groups --json
# Star / unstar contacts
gro contacts star people/c123 people/c456
gro contacts unstar people/c123
gro contacts search "John" --ids | gro contacts star --stdin
# Add / remove from groups
gro contacts add-to-group "Friends" people/c123 people/c456
gro contacts remove-from-group "Friends" people/c123
gro contacts add-to-group "VIP" --query "John"
Drive Commands
All Drive commands are under gro drive (or gro files):
# List files in root or folder
gro drive list
gro files list --max 20
gro drive list --type document
gro drive list --ids # Output file IDs only
# Search files
gro drive search "quarterly report"
gro files search --name "budget" --type spreadsheet
gro drive search --modified-after 2024-01-01
gro drive search "budget" --ids # Output file IDs only
# Get file metadata
gro drive get
gro files get --json
# Download files
gro drive download
gro files download --output ./report.pdf
gro drive download --format pdf # Export Google Doc as PDF
gro drive download --stdout # Write to stdout
# Show folder tree
gro drive tree
gro files tree --depth 3
gro drive tree --files # Include files, not just folders
# Star / unstar files
gro drive star
gro drive unstar
gro drive search "budget" --ids | gro drive star --stdin
Shared Drives
gro supports Google Shared Drives (formerly Team Drives). By default, search includes files from all drives you have access to.
# List available shared drives
gro drive drives
gro drive drives --json
# Search all drives (default)
gro drive search "quarterly report"
# Search only your personal drive
gro drive search "quarterly report" --my-drive
# Search a specific shared drive by name
gro drive search "budget" --drive "Finance Team"
gro drive list --drive "Engineering"
gro drive tree --drive "Marketing"
The --my-drive and --drive flags are mutually exclusive. Shared drive names are cached locally for fast lookups. Run gro drive drives to refresh the cache.
Bulk Operations
All organizational commands (archive, star, label, etc.) accept IDs through three input modes:
# 1. Positional arguments
gro mail archive id1 id2 id3
# 2. Stdin (pipe from search/list with --ids)
gro mail search "from:noreply older_than:30d" --ids | gro mail archive --stdin
gro contacts search "John" --ids | gro contacts star --stdin
gro drive search "budget" --ids | gro drive star --stdin
# 3. Inline query (resolved automatically)
gro mail archive --query "from:noreply older_than:30d"
gro contacts add-to-group "VIP" --query "John"
gro drive star --query "budget"
All organizational commands also support --dry-run / -n to preview changes without applying them.
Display cache status including location, TTL, and cached data status.
Usage: gro config cache show [flags]
Flags:
-j, --json Output as JSON
gro config cache clear
Remove all cached data. Cache will be repopulated on next use.
Usage: gro config cache clear
gro config cache ttl
Set the cache time-to-live in hours.
Usage: gro config cache ttl
gro mail search
Search for Gmail messages using Gmail's search syntax.
Usage: gro mail search [flags]
Flags:
-m, --max int Maximum number of results (default 10)
--ids Output only message IDs (one per line, for piping)
-j, --json Output as JSON
--ids and --json are mutually exclusive.
gro mail read
Read the full content of a Gmail message by its ID.
Usage: gro mail read [flags]
Flags:
-j, --json Output as JSON
gro mail thread
Read all messages in a Gmail conversation thread.
Usage: gro mail thread [flags]
Flags:
-j, --json Output as JSON
gro mail labels
List all Gmail labels including user labels and system categories.
Usage: gro mail labels [flags]
Flags:
-j, --json Output as JSON
gro mail attachments list
List all attachments in a Gmail message.
Usage: gro mail attachments list [flags]
Flags:
-j, --json Output as JSON
gro mail attachments download
Download attachments from a Gmail message.
Usage: gro mail attachments download [flags]
Flags:
-f, --filename string Download only this attachment
-o, --output string Output directory (default ".")
-a, --all Download all attachments
-e, --extract Extract zip files after download
gro mail archive
Archive messages (remove from inbox).
Usage: gro mail archive [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail star
Star messages.
Usage: gro mail star [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail unstar
Unstar messages.
Usage: gro mail unstar [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail mark-read
Mark messages as read.
Usage: gro mail mark-read [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail mark-unread
Mark messages as unread.
Usage: gro mail mark-unread [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail label
Add a label to messages.
Usage: gro mail label [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro mail unlabel
Remove a label from messages.
Usage: gro mail unlabel [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
Usage: gro mail categorize [message-ids...] [flags]
Flags:
-n, --dry-run Preview without making changes
--stdin Read message IDs from stdin
--query Search query to resolve message IDs
-j, --json Output results as JSON
gro calendar list
List all calendars the user has access to.
Usage: gro calendar list [flags]
Aliases: gro cal list
Flags:
-j, --json Output as JSON
gro calendar events
List events from a calendar.
Usage: gro calendar events [calendar-id] [flags]
Aliases: gro cal events
Flags:
-c, --calendar string Calendar ID to query (default "primary")
-m, --max int Maximum number of events (default 10)
--from string Start date (YYYY-MM-DD)
--to string End date (YYYY-MM-DD)
-j, --json Output as JSON
gro calendar get
Get the full details of a calendar event.
Usage: gro calendar get [flags]
Aliases: gro cal get
Flags:
-c, --calendar string Calendar ID containing the event (default "primary")
-j, --json Output as JSON
gro calendar today
Show all events for today.
Usage: gro calendar today [flags]
Aliases: gro cal today
Flags:
-c, --calendar string Calendar ID to query (default "primary")
-j, --json Output as JSON
gro calendar week
Show all events for the current week (Monday to Sunday).
Usage: gro calendar week [flags]
Aliases: gro cal week
Flags:
-c, --calendar string Calendar ID to query (default "primary")
-j, --json Output as JSON
gro calendar rsvp
Update your RSVP status on an event. Valid responses: accept, decline, tentative.
Usage: gro calendar rsvp [flags]
Aliases: gro cal rsvp
Flags:
-c, --calendar string Calendar ID containing the event (default "primary")
-n, --dry-run Preview without making changes
-j, --json Output as JSON
Usage: gro calendar color [flags]
Aliases: gro cal color
Flags:
-c, --calendar string Calendar ID containing the event (default "primary")
-n, --dry-run Preview without making changes
-j, --json Output as JSON
gro contacts list
List all contacts sorted by last name.
Usage: gro contacts list [flags]
Aliases: gro ppl list
Flags:
-m, --max int Maximum number of contacts (default 10)
--ids Output only resource names (one per line, for piping)
-j, --json Output as JSON
--ids and --json are mutually exclusive.
gro contacts search
Search contacts by name, email, phone, or organization.
Usage: gro contacts search [flags]
Aliases: gro ppl search
Flags:
-m, --max int Maximum number of results (default 10)
--ids Output only resource names (one per line, for piping)
-j, --json Output as JSON
--ids and --json are mutually exclusive.
gro contacts get
Get the full details of a specific contact.
Usage: gro contacts get [flags]
Aliases: gro ppl get
Flags:
-j, --json Output as JSON
gro contacts groups
List all contact groups (labels).
Usage: gro contacts groups [flags]
Aliases: gro ppl groups
Flags:
-m, --max int Maximum number of groups (default 30)
-j, --json Output as JSON
gro contacts star
Star contacts.
Usage: gro contacts star [contact-ids...] [flags]
Aliases: gro ppl star
Flags:
-n, --dry-run Preview without making changes
--stdin Read contact IDs from stdin
--query Search query to resolve contact IDs
-j, --json Output results as JSON
gro contacts unstar
Unstar contacts.
Usage: gro contacts unstar [contact-ids...] [flags]
Aliases: gro ppl unstar
Flags:
-n, --dry-run Preview without making changes
--stdin Read contact IDs from stdin
--query Search query to resolve contact IDs
-j, --json Output results as JSON
gro contacts add-to-group
Add contacts to a group.
Usage: gro contacts add-to-group [contact-ids...] [flags]
Aliases: gro ppl add-to-group
Flags:
-n, --dry-run Preview without making changes
--stdin Read contact IDs from stdin
--query Search query to resolve contact IDs
-j, --json Output results as JSON
gro contacts remove-from-group
Remove contacts from a group.
Usage: gro contacts remove-from-group [contact-ids...] [flags]
Aliases: gro ppl remove-from-group
Flags:
-n, --dry-run Preview without making changes
--stdin Read contact IDs from stdin
--query Search query to resolve contact IDs
-j, --json Output results as JSON
gro drive list
List files in Google Drive root or a specific folder.
Usage: gro drive list [folder-id] [flags]
Aliases: gro files list
Flags:
-m, --max int Maximum number of files (default 25)
-t, --type string Filter by type (document, spreadsheet, presentation, folder, pdf, image, video, audio)
--ids Output only file IDs (one per line, for piping)
--my-drive List from My Drive only
--drive string List from specific shared drive (name or ID)
-j, --json Output as JSON
--ids and --json are mutually exclusive. --my-drive and --drive are mutually exclusive.
gro drive search
Search for files in Google Drive. By default, searches all drives you have access to.
Usage: gro drive search [query] [flags]
Aliases: gro files search
Flags:
-n, --name string Search by filename only
-t, --type string Filter by file type
--owner string Filter by owner (me, or email)
--modified-after string Modified after date (YYYY-MM-DD)
--modified-before string Modified before date (YYYY-MM-DD)
--in-folder string Search within folder ID
--ids Output only file IDs (one per line, for piping)
--my-drive Search only My Drive
--drive string Search specific shared drive (name or ID)
-m, --max int Maximum results (default 25)
-j, --json Output as JSON
--ids and --json are mutually exclusive. --my-drive and --drive are mutually exclusive.
gro drive get
Get detailed metadata for a file.
Usage: gro drive get [flags]
Aliases: gro files get
Flags:
-j, --json Output as JSON
gro drive download
Download a file or export a Google Workspace file.
Usage: gro drive download [flags]
Aliases: gro files download
Flags:
-o, --output string Output file path
-f, --format string Export format for Google Workspace files
--stdout Write to stdout instead of file
Export formats for Google Workspace files:
Documents: pdf, docx, txt, html, md, rtf, odt
Spreadsheets: pdf, xlsx, csv, tsv, ods
Presentations: pdf, pptx, odp
Drawings: pdf, png, svg, jpg
gro drive tree
Display folder structure as a tree.
Usage: gro drive tree [folder-id] [flags]
Aliases: gro files tree
Flags:
-d, --depth int Maximum depth to traverse (default 2)
--files Include files in addition to folders
--my-drive Show My Drive only (default)
--drive string Show tree from specific shared drive
-j, --json Output as JSON
gro drive drives
List all shared drives accessible to you.
Usage: gro drive drives [flags]
Aliases: gro files drives
Flags:
--refresh Force refresh from API (ignore cache)
-j, --json Output as JSON
gro drive star
Star files.
Usage: gro drive star [file-ids...] [flags]
Aliases: gro files star
Flags:
-n, --dry-run Preview without making changes
--stdin Read file IDs from stdin
--query Search query to resolve file IDs
-j, --json Output results as JSON
gro drive unstar
Unstar files.
Usage: gro drive unstar [file-ids...] [flags]
Aliases: gro files unstar
Flags:
-n, --dry-run Preview without making changes
--stdin Read file IDs from stdin
--query Search query to resolve file IDs
-j, --json Output results as JSON
gro supports tab completion for bash, zsh, fish, and PowerShell.
Bash
# Load in current session
source <(gro completion bash)
# Install permanently (Linux)
gro completion bash | sudo tee /etc/bash_completion.d/gro > /dev/null
# Install permanently (macOS with Homebrew)
gro completion bash > $(brew --prefix)/etc/bash_completion.d/gro
Zsh
# Load in current session
source <(gro completion zsh)
# Install permanently
mkdir -p ~/.zsh/completions
gro completion zsh > ~/.zsh/completions/_gro
# Add to ~/.zshrc if not already present:
# fpath=(~/.zsh/completions $fpath)
# autoload -Uz compinit && compinit
Fish
# Load in current session
gro completion fish | source
# Install permanently
gro completion fish > ~/.config/fish/completions/gro.fish
PowerShell
# Load in current session
gro completion powershell | Out-String | Invoke-Expression
# Install permanently (add to $PROFILE)
gro completion powershell >> $PROFILE
Configuration
Configuration files are stored in ~/.config/google-readonly/:
File
Description
credentials.json
OAuth client credentials (from Google Cloud Console)
token.json
OAuth access/refresh token (fallback if keychain unavailable)
config.json
User settings (cache TTL, etc.)
cache/
Cached API metadata for faster repeated lookups
Cache Settings
gro caches Drive metadata (like shared drive lists) to speed up repeated commands. The cache TTL is configured during gro init (default: 24 hours).
# View cache status
gro config cache show
# Clear cache
gro config cache clear
# Change cache TTL
gro config cache ttl 12 # Set to 12 hours
The cache is automatically repopulated when stale or after being cleared.
Security
This tool is non-destructive by design - no send, delete, or trash operations are possible
Organizational operations (archive, label, star, RSVP, color, group management) are the most impactful actions available
OAuth tokens are stored in system keychain (macOS Keychain / Linux secret-tool) when available
File-based storage uses 0600 permissions
Credentials never leave your machine
Zip extraction includes security safeguards (size limits, path traversal prevention)
Troubleshooting
"Unable to read credentials file"
Ensure credentials.json exists:
ls -la ~/.config/google-readonly/credentials.json
"Token has been expired or revoked"
Clear the token and re-authenticate:
gro config clear
gro init
"Access blocked: This app's request is invalid"
Your OAuth consent screen may not be properly configured. Ensure:
All required APIs are enabled (Gmail, Calendar, People, Drive)
Your email is added as a test user (for apps in testing mode)
The required scopes are added
"API has not been used in project" or "SERVICE_DISABLED"
The specific Google API hasn't been enabled in your Cloud project:
Check the error message for the activation URL
Visit the URL and click Enable
Wait a few minutes for propagation
Clear your token and re-authenticate:
gro config clear
gro init
"Request had invalid authentication credentials"
Your token may be missing scopes for a newly added service. Clear and re-authenticate:
gro config clear
gro init
Token expires every 7 days
Your OAuth app is likely still in "Testing" mode. See Publish Your OAuth App in the setup guide. Apps in testing mode have tokens that expire after 7 days.