`gws`: The Google Workspace CLI That Builds Itself From Google’s API Catalog
A runtime-discovered command tree, schema validation, auto-pagination, and agent skills make `gws` feel less like a wrapper and more like a compiler for Workspace operations.
- `gws` is unusual because it derives its command surface from Google’s Discovery Documents instead of freezing endpoints into a hand-built CLI.
- That runtime discovery model changes maintenance from release-driven updates to schema-driven adaptation.
- The executor is the proof that the idea is real: it validates inputs, builds requests, and paginates results from the same metadata source.
- The project is also intentionally agent-facing, which turns a terminal tool into a structured interface for models as well as humans.
The first thing to understand about `gws` is that it is not trying to be a prettier `curl` wrapper. It is trying to be a compiler for Google Workspace operations. It reads Google’s Discovery Documents, turns them into a live command tree, and uses that same schema to validate input, build requests, and stream results.
A CLI That Compiles Its Own Command Tree
In the repo, the core idea is simple to describe and unusually hard to get right. `commands.rs` walks a `RestDescription`, maps resources to nested subcommands, and maps methods to executable leaf commands. That is why `gws drive files list` is not just a nice mnemonic. It is the visible end of a machine that has already read the API’s shape.
// Conceptual shape of the dynamic command builder
fn build_cli(doc: &RestDescription) -> Command {
// resources become subcommands
// methods become leaf commands
// schemas drive validation and help text
// the tree is assembled from Discovery metadata
todo!()
}
Why Runtime Discovery Changes the Maintenance Model
| Axis | `gws` | Static CLIs |
|---|---|---|
| Command model | Derived at runtime from Discovery Documents | Hard-coded and versioned in releases |
| API updates | Can absorb new methods without rewriting every command | Requires manual code and release work |
| Validation | Uses schema metadata from the same source | Often partial or hand-maintained |
| Agent readiness | Skills and structured output are first-class | Usually added later, if at all |
| Primary tradeoff | More dynamic, more moving parts | Simpler to reason about, slower to evolve |
This is the real maintenance shift. When Google adds or changes an endpoint, `gws` does not need to be rebuilt around a frozen command list. It still caches discovery data for speed, but the source of truth is upstream. That makes the CLI feel less like a product release and more like a live projection of the API surface.
built for humans and agents
The Execution Engine Turns Flags Into Validated Requests
This is where the architecture stops sounding clever and starts sounding useful. The executor takes `params` and body JSON, validates them against Discovery schemas, builds the HTTP request with `reqwest`, and then handles pagination automatically when the user asks for all pages. The point is that the command tree and the request engine are not separate systems. They are two views of the same metadata.
// Execution flow, simplified
1. Parse CLI flags
2. Validate params/body against Discovery schema
3. Build reqwest request
4. Send request
5. If page-all is enabled, follow nextPageToken
6. Stream results as NDJSON
That matters because validation happens before the network round trip. If the JSON is wrong, `gws` can tell you locally. If the response is paginated, `gws` can keep going without making the user hand-roll loops. The runtime-discovered command tree is only half the story. The other half is that execution remains schema-aware all the way through.
The Other Big Idea: `gws` Is Built for Agents, Not Just Humans
The CLI no longer writes a fallback .encryption_key text file on macOS and Windows when securely storing credentials. Instead, it strictly uses the native OS keychain
The agent layer is not a side quest. It is part of the product shape. The repository includes a `skills/` directory and a `.agent/` workflow, which tells you the CLI is meant to be legible to models, not just convenient for people. `generate-skills` turns commands into structured instructions that an LLM can read and chain.
| Interface | What it optimizes for | Why it matters |
|---|---|---|
| Raw CLI commands | Power users and scripts | Compact, precise, and familiar |
| Skills files | LLM planning and tool use | Gives agents a readable action model |
| Structured JSON output | Machine consumption | Reduces prompt fragility and parsing guesswork |
| `.agent/` workflows | Verification and orchestration | Makes the tool easier to embed in agent loops |
That is a subtle but important move. Most CLIs assume the operator already knows the tool. `gws` assumes the operator may be a model that needs a clean contract. In that sense, the tool is not just a shell interface. It is a physical interface for a reasoning system.
Auth Is the Boring Problem `gws` Decided to Solve Well
Good infrastructure tools win or lose on setup. `gws` leans into that by automating the ugly parts of OAuth, project creation, and credential storage. It uses `aes-gcm` and keyring integration so secrets are handled with the kind of care that makes a terminal tool trustworthy enough to sit near real accounts.
That choice also changes adoption. A powerful CLI that is hard to authenticate becomes a demo. A powerful CLI that can guide users through auth becomes a habit. This is the sort of engineering that rarely gets a headline, but often decides whether a tool survives contact with real teams.
Why Rust Fits This Problem
Rust is not decorative here. `gws` deals with large discovery payloads, dynamic schema handling, concurrent network calls, and credential storage. Rust gives the project performance, type discipline, and a safer default for the parts that matter most when a CLI starts behaving like infrastructure.
| Need | Why Rust helps |
|---|---|
| Parsing and command assembly | Fast enough to handle discovery-driven trees without feeling heavy |
| Schema handling | Types help tame loosely structured API metadata |
| Credential safety | Memory safety pairs well with encrypted secret handling |
| CLI ergonomics | The ecosystem already has strong primitives for terminal apps and async networking |
The language choice is not the story by itself. It is the enabler. A dynamic CLI with validation, pagination, agent skills, and secure auth needs a runtime that can keep the moving parts contained.
How `gws` Compares to GAM, clasp, Nylas CLI, and CLI for Microsoft 365
| Tool | Category | Command model | Audience | Agent readiness |
|---|---|---|---|---|
| `gws` | Workspace CLI | Runtime-discovered from Google Discovery Docs | Humans and agents | Built in |
| GAM | Admin utility | Mostly static and admin-focused | Workspace administrators | Limited |
| clasp | Apps Script tool | Static, code-project oriented | Developers writing Apps Script | Not the focus |
| Nylas CLI | Multi-provider CLI | Provider-driven static surface | Teams wanting one abstraction | Modest |
| CLI for Microsoft 365 | Microsoft ecosystem CLI | Static command set | Microsoft admins and developers | Secondary |
The comparison is less about winners and losers than about category. GAM is the long-standing admin workhorse. clasp is for managing Apps Script projects. Nylas aims for multi-provider simplicity. CLI for Microsoft 365 covers a similar ecosystem with a static command set. `gws` is different because it is runtime-discovered, Rust-based, Workspace-native, and explicitly shaped for agent use.
That combination is the point. `gws` does not merely expose Workspace APIs. It tries to stay aligned with them as they change, then package that alignment into a terminal interface that both people and models can actually use.





