# Google Workspace CLI: An Agent-First Interface for the Google Workspace APIs


[Google's gws](https://github.com/google/gws) is a command-line interface designed specifically for AI agents interacting with Google Workspace. Unlike traditional CLIs built around human usability, `gws` optimizes for what agents actually need: predictable, structured input and output, minimal token overhead, and an always-current command surface that reflects the live state of the API rather than static documentation.

The tool was created by Justin Poehnelt, a Senior Developer Relations Engineer at Google, who outlined the design philosophy in a blog post titled "You Need to Rewrite Your CLI for AI Agents." The core argument is that human developer experience and agent developer experience have different, often conflicting requirements, and most existing CLIs are built entirely for humans.

![Blog post by Justin Poehnelt highlighting the distinction between Human DX and Agent DX](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/161b3174-e5aa-44eb-b3e6-eb8f8d8da700/lg2x =1920x1080)

<iframe width="100%" height="315" src="https://www.youtube.com/embed/EKG9kX86u0s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## Human DX vs. agent DX

Traditional CLIs prioritize discoverability and forgiveness. They offer extensive `--help` menus, accept loose input, suggest corrections for typos, and expose configuration through many specific flags. For a person, this is intuitive. For an agent, it is expensive: the agent must learn which of dozens of possible flags applies to each command, and reasoning through that consumes tokens and introduces ambiguity.

Agents benefit from the opposite: predictability and structure. They do not need friendly flag names. They need to construct a valid request from a known schema, receive deterministic output, and move on. `gws` was built around this distinction from the start.

## Key design decisions

### JSON payloads instead of bespoke flags

Rather than exposing configuration through individual flags, `gws` accepts a single `--json` or `--params` flag containing a raw JSON payload that maps directly to the underlying API request body. Compare the two approaches for creating a spreadsheet:

A traditional human-first CLI might look like this:

```command
some-cli sheets create --title "Q1 Budget" --locale "en_US" --sheet-title "January" --frozen-rows 1 --frozen-cols 2
```

The equivalent `gws` command:

```command
gws sheets spreadsheets create --json '{"properties": {"title": "Q1 Budget", "locale": "en_US"}, "sheets": [{"properties": {"title": "January", "gridProperties": {"frozenRowCount": 1, "frozenColumnCount": 2}}}]}'
```

![Comparison from the blog post showing the numerous flags of a human-first CLI versus the single JSON payload approach in gws](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/c75dfc76-fa30-4bc4-a6e0-694ba47e9600/orig =1920x1080)

For an agent, constructing one JSON object from an API schema is far simpler than selecting from a large set of flags. It also reduces the number of distinct things the agent needs to learn about the tool's interface.

### Runtime schema introspection

Instead of consuming static documentation, an agent can query `gws` directly for the schema of any command using `gws schema`:

```command
gws schema drive.about.get
```

This returns a full JSON schema describing the method signature, accepted parameters, request body structure, and response types. The agent gets exactly the information it needs to construct a valid call, without any documentation being pre-loaded into its context. This keeps token usage low and ensures the agent is always working from the current API definition rather than a potentially outdated reference.

### Dynamically built command surface

`gws` does not ship with a hardcoded list of commands. Instead, it reads Google's [API Discovery Service](https://developers.google.com/discovery) at runtime, which provides a machine-readable description of all available Google Workspace APIs.

![Screenshot of the gws GitHub repository README with the line "gws doesn't ship a static list of commands... builds its entire command surface dynamically" highlighted](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/48c8ed3a-ab4a-410c-2b5b-0e20ffa93100/orig =1920x1080)

When Google adds a new endpoint or modifies an existing one, `gws` picks up the change automatically. There is no lag between an API update and the CLI reflecting it, which means agents are always operating against the current API surface rather than a snapshot that may be months out of date.

## Setting up `gws`

Getting `gws` running requires configuring OAuth credentials through the Google Cloud Platform. The steps below cover everything from installation to a verified login.

### Prerequisites

Before starting, you need a Google account with access to a Google Cloud Platform (GCP) project, the `gcloud` CLI installed and initialized, and Node.js and npm available on your system.

### Installing the CLIs

Install the `gcloud` CLI. On macOS with Homebrew:

```command
brew install --cask google-cloud-sdk
```

For other operating systems, follow the [official installation instructions](https://cloud.google.com/sdk/docs/install). After installation, run `gcloud init` to initialize it.

Install the `gws` CLI globally via npm:

```command
npm install -g @googleworkspace/cli
```

### Running the authentication setup wizard

Start the interactive setup wizard:

```command
gws auth setup
```

![The gws auth setup wizard in the terminal showing the multi-step process for authentication and project selection](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/617901f7-b3ce-46bc-a762-b7335a0caa00/lg2x =1920x1080)

The wizard walks through five steps: verifying that `gcloud` is installed, selecting a Google account, selecting a GCP project, choosing which Workspace APIs to enable (Drive, Gmail, Sheets, Calendar, etc.), and then pausing to request an OAuth Client ID and Client Secret. Those credentials need to be generated in the GCP Console before the wizard can complete.

### Creating OAuth 2.0 credentials in the GCP Console

In the [GCP Console](https://console.cloud.google.com/), navigate to **APIs & Services > Credentials**. Click **+ CREATE CREDENTIALS**, select **OAuth client ID**, set **Application type** to **Desktop app**, give it a name such as `gws-cli-creds`, and click **Create**.

A dialog will appear containing a **Client ID** and a **Client Secret**.

![The "OAuth client created" dialog in the Google Cloud Console displaying the Client ID and Client Secret](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/6ab9a014-eff3-42ed-b9cf-60aa34dcb200/public =1920x1080)

Paste the **Client ID** into the waiting wizard prompt, press `Enter`, then paste the **Client Secret** and press `Enter` again. The wizard will then prompt you to run `gws auth login` to complete the flow, but there are two more GCP Console steps to handle first.

### Configuring the redirect URI and test users

`gws` uses a local web server to receive the authentication token from Google. Run the login command to generate the authentication URL:

```command
gws auth login
```

Do not open the URL yet. Find the `redirect_uri` parameter near the end of the URL. It will look something like `redirect_uri=http://localhost:51065`. Note the port number.

Back in the GCP Console, open the OAuth client ID you just created and add the full localhost address (e.g., `http://localhost:51065`) under **Authorized redirect URIs**, then click **Save**.

![The GCP Console page for editing an OAuth client ID with the Authorized redirect URIs field highlighted](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/46fce730-5c47-48b6-9fc6-85d1e3c4d200/md1x =1920x1080)

If your OAuth consent screen is in **Testing** mode (the default for new projects), navigate to **APIs & Services > OAuth consent screen** and add your Google email address under **Test users**. Without this, Google will block the authentication flow.

Once both changes are saved, copy the full URL that `gws auth login` generated, paste it into your browser, and complete the sign-in and permissions flow. Your terminal should display a JSON object with `"status": "success"`. Verify the authenticated account with:

```command
gws auth list
```

## Working examples

### Fetching recent emails

An agent asked to summarize the latest ten emails would run:

```command
gws gmail users messages list --params '{"userId": "me", "maxResults": 10}'
```

This returns a list of message IDs. The agent then fetches metadata for each one and presents a summary:

```text
[output]
#: 1
From: Joules
Subject: Starts Today! Mid-Season Sale. Get up to 40% off!
Date: Fri 6 Mar, 09:58
Labels: Promotions, UNREAD

#: 2
From: Charles Aji (Substack)
Subject: Reducing the Cost of Your Intelligence
Date: Fri 6 Mar, 09:53
Labels: Updates, UNREAD
. . .
```

The entire operation requires a small number of API calls with no ambiguity in how to invoke them.

### Creating a draft email in Gmail

The Gmail API requires messages to be formatted as MIME and base64-encoded before submission. An agent handling a request to draft a poem-based email would construct the encoded payload and pass it to `gws`:

```command
gws gmail users drafts create --params '{"userId": "me"}' --json '{"message": {"raw": "<base64-encoded-mime-message>"}}'
```

![The newly created draft email in Gmail showing the subject and poem body](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/91545d5b-65ed-4994-024e-091c92f95f00/md1x =1920x1080)

The draft appears immediately in the Gmail drafts folder. The agent determines the correct command structure by querying `gws schema gmail.users.drafts.create` rather than consulting external documentation.

### Building a Google Slides presentation

An agent tasked with creating a five-slide presentation with cat images would chain several `gws` commands. The first creates the blank presentation:

```command
gws slides presentations create --json '{"title": "Claude Cats"}'
```

The response includes a `presentationId`. Subsequent calls to `presentations.batchUpdate` add text to the title slide and insert images into the remaining four slides, each call passing the `presentationId` as a parameter and the relevant request body as a JSON payload.

![Completed "Claude Cats" presentation in Google Slides showing the title slide and cat image slide thumbnails](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/25514300-e70a-468d-fe9b-49a4926bb200/orig =1920x1080)

The agent discovers the correct structure for each `batchUpdate` request by querying the schema at runtime, keeping the entire operation self-contained within the CLI without needing pre-loaded API documentation.

## Final thoughts

`gws` is a practical example of what it looks like to design tooling explicitly for AI agents rather than adapting human-facing tools after the fact. **The combination of JSON-first input, runtime schema introspection, and a dynamically built command surface** solves real problems: token overhead from static documentation, stale tooling that lags behind API changes, and the cognitive cost of translating natural language tasks into bespoke flag combinations.

The initial OAuth setup is the main friction point. Once that is behind you, **the interface is consistent and the agent behavior is predictable**. For anyone building agents that need to interact with Google Workspace, `gws` is worth the setup time.

The project is still early, and the [GitHub repository](https://github.com/google/gws) is the best place to track its development and report issues.