Skip to content

Repository files navigation

Desk

Google Workspace from the command line — Gmail, Drive, Sheets, Docs, Calendar, and Forms. Unix philosophy: simple commands that compose with pipes.

Quick Start

uv tool install git+https://github.com/robpc/desk
desk setup
desk mail search "is:unread"

Installation

Recommended: uv (fastest)

uv tool install git+https://github.com/robpc/desk

Alternative: pipx

pipx install git+https://github.com/robpc/desk

Alternative: pip + venv

python3 -m venv ~/.local/share/desk-venv
~/.local/share/desk-venv/bin/pip install git+https://github.com/robpc/desk
mkdir -p ~/.local/bin
ln -sf ~/.local/share/desk-venv/bin/desk ~/.local/bin/desk

Don't have Python?

Install uv — it manages Python for you:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install git+https://github.com/robpc/desk

Troubleshooting

externally-managed-environment error: Your system Python is managed by Homebrew (or similar). Use uv or pipx instead of pip install directly.

desk: command not found after install: ~/.local/bin may not be on your PATH. Add it:

# zsh (macOS default)
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc

# bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc

Setup

Quick (gcloud users)

If you have gcloud installed and authenticated:

desk setup --gcloud

Standard (team credentials)

Get credentials.json from your team (e.g., 1Password vault):

desk setup --credentials ~/Downloads/credentials.json

From scratch (create your own)

This takes about 10 minutes the first time.

  1. Go to Google Cloud Console and create a project
  2. Go to APIs & Services → Library and enable: Gmail API, Google Drive API, Google Sheets API, Google Docs API, Google Calendar API, Google Forms API, Google Slides API, Google Meet REST API
  3. Go to APIs & Services → Credentials → Create Credentials → OAuth client ID
  4. If prompted, configure the OAuth consent screen (User type: External, App name: "Desk")
  5. Application type: Desktop app, Name: "Desk", click Create
  6. Download the JSON file, then:
mkdir -p ~/.desk
mv ~/Downloads/client_secret_*.json ~/.desk/credentials.json
desk auth login

Already have a project from an earlier install? desk slides and desk meet need the Google Slides API and Google Meet REST API enabled in that same project (the Library page above), then desk auth login again to grant their scopes. A disabled API shows up as a 403 ... has not been used in project error from Google, not as a missing scope.

Signing out and resetting

desk auth status          # Shows the configured client_id, the token's client_id, missing scopes
desk auth logout          # Remove the OAuth token; keep the client credentials
desk auth clear --yes     # Remove token and client credentials (--token / --client to pick one)

If auth status says the token's client_id doesn't match the configured client, the token can't refresh — desk auth logout then desk auth login fixes it.

Usage

Discovering commands

desk --help                    # All command groups
desk mail --help               # All mail commands
desk mail search --help        # Detailed help for a command

Checking which build you have

desk --version
# desk, version 0.3.0 (a837d65, 2026-09-03)

desk --version --json          # Same, as fields

The commit is baked in at build time, so it identifies the build even when installed straight from git — where the version number alone cannot, since that install tracks a branch rather than a release. It is also how to confirm uv tool upgrade desk actually changed anything.

desk --capabilities all reports the same commit alongside the machine-readable command list, so a script can check whether a fix is present before relying on it.

Mail (Gmail)

desk mail search "from:boss" --max 10    # Search messages
desk mail unread                         # Unread messages
desk mail read <id>                      # Read a message
desk mail threads "from:boss"            # Search by thread
desk mail thread <thread-id>             # Read entire conversation
desk mail send --to "user@example.com" --subject "Hello" --body "Message"
desk mail reply <id> --body "Thanks!"
desk mail forward <id> --to "colleague@example.com" --body "FYI"
desk mail drafts                         # List drafts
desk mail labels                         # List labels
desk mail archive <id>...                # Archive messages
desk mail trash <id>...                  # Move to trash
desk mail star <id>...                   # Star messages
desk mail label <label> <id>...          # Add a label
desk mail attachments <id>               # List attachments
desk mail download-attachments <id> --output-dir ./files/

Drive

desk drive search "name contains 'report'"   # Search files
desk drive recent --max 10                    # Recently modified files
desk drive read <file-id>                     # Read file content
desk drive info <file-id>                     # File metadata
desk drive upload report.pdf                  # Upload a file
desk drive download <file-id>                 # Download a file
desk drive mkdir "Project Files"              # Create a folder
desk drive move <file-id> <folder-id>         # Move file to folder
desk drive trash <file-id>                    # Move to trash
desk drive share <file-id> bob@co.com         # Share with someone

Sheets

desk sheets read <spreadsheet-id>                    # Read entire first sheet
desk sheets read <id> --range "Sheet1!A1:C10"        # Read specific range
desk sheets update-cell <id> "Sheet1!A1" "New value" # Update a cell
desk sheets create "Q1 Budget"                       # Create spreadsheet
desk sheets write <id> "Sheet1!A1:B2" '[["A","B"],["1","2"]]'
desk sheets append <id> "Sheet1!A:Z" '[["Alice","30"]]'
desk sheets clear <id> "Sheet1!A1:C10"               # Clear a range

Docs

desk docs create "Meeting Notes"                 # Create a doc
desk docs read <document-id>                     # Read document
desk docs update <id> "Appended text"            # Append text
desk docs update <id> "New" --mode replace       # Replace all content
desk docs export <id> report.pdf                 # Export as PDF
desk docs export <id> notes.txt --format txt     # Export as text

Calendar

desk cal today                    # Today's events
desk cal week                     # This week's events
desk cal next --max 5             # Upcoming events
desk cal list                     # List calendars
desk cal find "standup"           # Search events
desk cal create "Meeting" --start 2024-01-15T10:00:00 --end 2024-01-15T11:00:00
desk cal create "Training" --start ... --end ... --meet --hide-guest-list
desk cal update <event-id> --summary "New Title"
desk cal update <event-id> --meet            # Add a Meet link to an existing event
desk cal delete <event-id> --send-updates none   # Delete without mailing attendees
desk cal delete <event-id>

# Any command takes -c/--calendar: a calendar ID, a friendly name from
# `desk cal list` (case-insensitive), or 'primary' (the default).
desk cal today -c Family                            # Read a shared calendar
desk cal create "Dinner" -c Family \
  --start 2024-01-15T18:00:00 --end 2024-01-15T20:00:00
desk cal update <event-id> -c Family --summary "Late dinner"
desk cal delete <event-id> -c Family

Meet

Meeting-space settings — recording and transcription. Needs the Google Meet REST API enabled in your Cloud project (see Setup) and a scope older tokens don't have, so run desk auth login again if desk meet reports a missing scope.

# The conferenceId from a cal read addresses the space
desk cal create "Training" --start ... --end ... --meet --json
desk meet read abc-defg-hij                  # Current settings
desk meet update abc-defg-hij --auto-record on --auto-transcript on
desk meet update abc-defg-hij --auto-record default   # Defer to your Workspace policy

Co-hosts are UI-only — Google restricts the Meet space-members API to its Developer Preview Program. See desk meet --help.

Forms

desk forms create "Survey"                       # Create a form
desk forms read <form-id>                        # Read form structure
desk forms responses <form-id>                   # List responses
desk forms add-question <form-id> "Your name?" --type short-answer
desk forms add-section <form-id> "Part 2"        # Add a section

Batch Operations

desk mail archive ID1 ID2 ID3                                                    # Multiple IDs
desk mail search "from:notifications" --json | jq -r '.[].id' | desk mail archive --stdin  # Pipe
desk mail modify ID1 ID2 --remove-label INBOX --remove-label UNREAD              # Combine

Output Formats

All commands support --json for machine-readable output:

desk mail search "is:unread" --json
desk drive recent --json
desk cal today --json

Migrating from gmail-cli

If you previously used gmail, Desk will auto-migrate your config from ~/.gmail-cli/ to ~/.desk/ on first run. You'll need to re-authenticate to grant the expanded scopes (Drive, Sheets, Docs, Calendar).

Development

git clone https://github.com/robpc/desk
cd desk
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest

# Lint
ruff check src/

License

Copyright 2026 Robert Cannon

Licensed under the Apache License, Version 2.0. See LICENSE for the full text.

About

Google Workspace from the command line — Gmail, Drive, Sheets, Docs, Calendar, and Forms. Unix philosophy: simple commands that compose with pipes.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages