WebCLI

Article · CLI Review

gws CLI Review

72
WebCLI Score
Strong foundation; three fixable gaps keep it from a higher score.
How scores work →

gws is Google's open-source command-line interface for the Google Workspace APIs: Drive, Gmail, Calendar, Sheets, Docs, Chat, and more. It launched on March 2, 2026 and reached 14,600+ GitHub stars within days. Its stated design goals set it apart from most CLIs: it is explicitly built for AI agent / MCP tool-calling, and it derives its entire command tree dynamically from Google's Discovery Documents rather than hand-coding each subcommand.

That design context matters. A fair critique requires distinguishing between patterns that apply universally and patterns that conflict with gws's intentional architecture. This review does both.

What this review is

An analysis of gws --help, gws <service> --help, and gws <service> <resource> <method> --help against the WebCLI design patterns synthesized from git, bash, curl, npm, docker, pip, grep, ssh, wget, and make.


Scoring methodology

Every WebCLI review assigns a score from 0 to 100. The score is calculated across ten standard dimensions, each worth 10 points. Pass = 10 pts, Partial = 5 pts, Fail = 0 pts. Intentional tradeoff = 5 pts; these are not penalized as failures, but full credit requires a full pass.

#DimensionWhat is checkedPoints
1Help system-h/--help works at every level of the command tree; consistent renderer0–10
2--version--version and -V both present and correct0–10
3Verbose flag-v/--verbose intercepted and handled; not misrouted or silently dropped0–10
4Quiet flag-q/--quiet suppresses non-data output; safe for piping and CI0–10
5Output streamsErrors go to stderr; data goes to stdout; exit codes non-zero on failure0–10
6Machine-readable outputJSON (or equivalent) output available; safely pipeable to jq0–10
7Exit codesDistinct exit codes documented in --help; caller can branch without parsing text0–10
8Flag namingKebab-case flags; no camelCase leaks; short aliases consistent0–10
9Subcommand structureConsistent verb/noun or noun/verb pattern; predictable discovery0–10
10ComposabilityPipeable output, --dry-run, shell completion, or equivalent scripting options0–10

All ten reviewed CLIs are ranked on the CLI Rankings page.


Scorecard

Design RuleStatusNotes
-h / --helpPassWorks at every level of the command tree
--versionPassPrints version correctly
-V short version flagPartial--version works; -V is absent
-v / --verboseFail-v is parsed as a service name and returns a validation error
-q / --quietFailAbsent entirely; relevant for scripting and agent use
--dry-runPassPresent on every resource subcommand
-o / --outputPartialPresent but scoped to binary file downloads only
Errors → stderrPassConsistent throughout
Exit codes documentedPassFive distinct codes; exceeds the standard
JSON-first outputPassJSON is the default; --format supports table, yaml, csv
Consistent help renderingFailRoot help is hand-crafted text; subcommand help is clap-generated (two different formats)
Subcommand structureIntentional tradeoffSee analysis below
--params <JSON> blobIntentional tradeoffSee analysis below
Verb vocabulary / kebab-casePartialStandard verbs mixed with camelCase API names (emptyTrash, generateIds)
--config <file>Intentional tradeoffEnv vars preferred for agent/container environments
Env var naming consistencyPartialGOOGLE_WORKSPACE_PROJECT_ID breaks the _CLI_ prefix used by all other vars

What it does well

Help system

Both gws --help and gws -h work, and the pattern cascades cleanly through the full command tree: gws drive --help, gws drive files --help, gws drive files list --help all produce relevant output. This matches the highest-confidence help pattern from the design guide.

Exit codes

gws documents five distinct exit codes in its top-level help, a level of specificity that exceeds every tool in the reference set:

CodeMeaning
0Success
1API error — Google returned an error response
2Auth error — credentials missing or invalid
3Validation — bad arguments or input
4Discovery — could not fetch API schema
5Internal — unexpected failure

This is excellent for agent use: a calling system can branch on exit code without parsing error text.

JSON-first output

JSON is the default output format, not an opt-in. --format also accepts table, yaml, and csv. All responses are immediately pipeable to jq. The --page-all flag streams paginated results as NDJSON, a composability feature none of the canonical ten tools offer.

--dry-run

Present on every resource subcommand (not just the top level). Validates a request locally without sending it to Google's API. Essential for an agent that might construct requests programmatically.

Environment variables

All eleven environment variables are documented in the top-level --help output: a practice that the canonical ten tools do inconsistently at best.


Real problems

These are not tradeoffs. They are gaps that conflict with gws's own stated goals.

-v is routed to the service parser

Running gws -v returns a structured JSON validation error:

{"error":{"code":400,"message":"Unknown service '-v'. Known services: drive, sheets, ...","reason":"validationError"}}

-v / --verbose is a "Very high" confidence flag, one that an LLM will generate reflexively. Routing it into the service parser and returning an API-style error is the worst possible outcome: it is confusing, it exits non-zero, and the error message implies the user typed a wrong API name. The flag should be intercepted at the top level before service dispatch.

--quiet is absent

There is no -q / --quiet flag. For a tool explicitly designed for AI agents and scripting, suppressing non-data output is table stakes. The design guide rates this 8/10 across the canonical CLIs. Its absence is more damaging here than it would be for a human-facing tool.

Two different help renderers

gws --help produces hand-crafted prose. gws drive --help produces clap-formatted output with Usage:, Commands:, and Options: headers. The visual language, section names, and flag formatting differ between the two. A tool (or LLM) that parses --help output to understand command structure sees two incompatible schemas within the same binary.


Intentional tradeoffs

These patterns diverge from the design guide but for clear architectural reasons.

Subcommand structure: <service> <resource> <method>

The design guide recommends <verb> <noun> (git/docker/npm style). gws uses <service> <resource> <method> (noun-first, verb-last):

gws drive files list
gws gmail users messages list

This is the right tradeoff here. gws derives its entire command tree dynamically from Google's Discovery Documents. That structure is service → resource → method. Inverting it to verb-first would break the 1:1 mapping that makes the tool self-updating and keeps it in sync with Google's own API documentation. For an agent that needs to cross-reference the Google API docs, structural fidelity is more valuable than verb-first familiarity.

--params <JSON> instead of individual flags

The design guide recommends individual named flags for parameters. gws bundles all query parameters into a single JSON blob:

gws drive files list --params '{"pageSize": 10, "q": "mimeType=\"application/pdf\""}'

For a statically-defined CLI, this would be an antipattern. For a dynamically-generated CLI that maps to hundreds of Google API methods, each with their own parameter sets, it is a reasonable choice. The companion gws schema drive.files.list command gives agents a machine-readable parameter schema: the intended workflow is schema-first discovery, not flag guessing.

No --config <file> flag

The design guide recommends a --config flag. gws uses GOOGLE_WORKSPACE_CLI_CONFIG_DIR instead. In agent and container environments (the primary deployment target), environment variables are the standard credential injection mechanism. Secrets managers, CI systems, and Kubernetes all inject via env vars, not config flags. This is the right call for this tool's audience.

camelCase subcommand names

Subcommands like emptyTrash, generateIds, and modifyLabels violate the kebab-case convention. But they mirror Google's API method names exactly, which means any developer reading the Google API documentation can predict the correct subcommand without guessing. The tradeoff is correctness of API mapping over CLI naming convention, reasonable for a tool whose primary documentation is the Google API reference.


Summary

gws makes conscious, defensible architectural decisions that diverge from the conventional CLI playbook, and most of those decisions are correct given its design goals. The real problems are narrower: -v being mis-routed into the service parser, the absence of --quiet, and the inconsistent help rendering. None of those are architectural tradeoffs; they are just gaps.

The exit code design, JSON-first output, --page-all NDJSON streaming, and per-command --dry-run are genuinely ahead of the reference set. For a tool released in its first two weeks of life at v0.16.0, the base is solid.

WebCLI Spec · Draft v0.1 · March 2026 · GitHub · Released under CC BY 4.0 · Authored by @chandler212