- e1505af: Remove multi-account, domain-wide delegation, and impersonation support. Removes
gws auth list,gws auth default,--accountflag,GOOGLE_WORKSPACE_CLI_ACCOUNTandGOOGLE_WORKSPACE_CLI_IMPERSONATED_USERenv vars.
- 54b3b31: Move x-goog-user-project header from default client headers to API request builder, fixing Discovery Document fetches failing with 403 when the quota project lacks certain APIs enabled
-
322529d: Document all environment variables and enable GOOGLE_WORKSPACE_CLI_CONFIG_DIR in release builds
-
2173a92: Send x-goog-user-project header when using ADC with a quota_project_id
-
1f47420: fix: extract CLA label job into dedicated workflow to prevent feedback loop
The Automation workflow's
check_run: [completed]trigger caused a feedback loop — every workflow completion fired a check_run event, re-triggering Automation, which produced another check_run event, and so on. Moving the CLA label job to its owncla.ymlworkflow eliminates the trigger from Automation entirely. -
132c3b1: fix: warn on credential file permission failures instead of ignoring
Replaced silent
let _ =onset_permissionscalls insave_encryptedwitheprintln!warnings so users are aware if their credential files end up with insecure permissions. Also log keyring access failures instead of silently falling through to file storage. -
a2cc523: Add
x86_64-unknown-linux-muslbuild target for Linux musl/static binary support -
c86b964: Fix multi-account selection: MCP server now respects
GOOGLE_WORKSPACE_CLI_ACCOUNTenv var (#221), and--accountflag before service name no longer causes parse errors (#181) -
ff53538: Fix scope selection to use first (broadest) scope instead of all method scopes, preventing gmail.metadata restrictions from blocking query parameters
-
c80eb52: Replace strip_suffix(".readonly").unwrap() with unwrap_or fallback
Two call sites used
.strip_suffix(".readonly").unwrap()which would panic if a scope URL marked asis_readonlydidn't actually end with ".readonly". While the current data makes this unlikely, usingunwrap_oris a defensive improvement that prevents potential panics from inconsistent discovery data. -
9a780d7: Log token cache decryption/parse errors instead of silently swallowing
Previously,
load_from_diskused four nestedif let Okblocks that silently returned an empty map on any failure. When the encryption key changed or the cache was corrupted, tokens silently stopped loading and users were forced to re-authenticate with no explanation.Now logs specific warnings to stderr for decryption failures, invalid UTF-8, and JSON parse errors, with a hint to re-authenticate.
-
6daf90d: Fix MCP tool schemas to conditionally include
body,upload, andpage_allproperties only when the underlying Discovery Document method supports them.bodyis included only when a request body is defined,uploadonly whensupportsMediaUploadis true, andpage_allonly when the method has apageTokenparameter. Also drops emptybody: {}objects that LLMs commonly send on GET methods, preventing 400 errors from Google APIs.
-
28fa25a: Clean up nits from PR #175 auth fix
- Update stale docstring on
resolve_accountto match new fallthrough behavior - Add breadcrumb comment on string-based error matching in
main.rs - Move identity scope injection before authenticator build for readability
- Update stale docstring on
-
88cb65c: chore: add automation workflow for auto-fmt, CLA labeling, and file-based PR triage
-
a926e3f: Fix auth failures when accounts.json registry is missing
Three related bugs caused all API calls to fail with "Access denied. No credentials provided" even after a successful
gws auth login:resolve_account()rejected validcredentials.encas "legacy" whenaccounts.jsonwas absent, instead of using them.main.rssilently swallowed all auth errors, masking real failures behind a generic message.auth logindidn't includeopenid/emailscopes, sofetch_userinfo_email()couldn't identify the user, causing credentials to be saved without anaccounts.jsonentry.
-
cb1f988: Add Content-Length: 0 header for POST/PUT/PATCH requests with no body to fix HTTP 411 errors
-
3d59b2e: fix: isolate flaky auth tests from host ADC credentials
-
b38b760: Add Application Default Credentials (ADC) support.
gwsnow discovers ADC as a fourth credential source, after the encrypted and plaintext credential files. The lookup order is:GOOGLE_WORKSPACE_CLI_TOKENenv var (raw access token, highest priority)GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILEenv var- Encrypted credentials (
~/.config/gws/credentials.enc) - Plaintext credentials (
~/.config/gws/credentials.json) - ADC —
GOOGLE_APPLICATION_CREDENTIALSenv var (hard error if file missing), then~/.config/gcloud/application_default_credentials.json(silent if absent)
This means
gcloud auth application-default login --client-id-file=client_secret.jsonis now a fully supported auth flow — no need to rungws auth loginseparately. Bothauthorized_userandservice_accountADC formats are supported.
- 9cf6e0e: Add
--tool-mode compact|fullflag togws mcp. Compact mode exposes one tool per service plus agws_discovermeta-tool, reducing context window usage from 200-400 tools to ~26.
- 0a16d0b: Add
-s/--servicesflag togws auth loginto filter the scope picker by service name (e.g.-s drive,gmail,sheets). Also expands the workspace admin scope blocklist to includechat.admin.*andclassroom.*patterns. - 5205467: fix(setup): drain stale keypresses between TUI screen transitions
- e1e08eb: Fix highlight color on light terminal themes by using reverse video instead of a dark-gray background
-
fc6bc95: Exclude Workspace-admin-only scopes from the "Recommended" scope preset.
Scopes that require Google Workspace domain-admin access (
apps.*,cloud-identity.*,ediscovery,directory.readonly,groups) now return400 invalid_scopewhen used by personal@gmail.comaccounts. These scopes are no longer included in the "Recommended" template, preventing login failures for non-Workspace users.Workspace admins can still select these scopes manually via the "Full Access" template or by picking them individually in the scope picker.
Adds a new
is_workspace_admin_scope()helper (mirroring the existingis_app_only_scope()) that centralises this detection logic. -
2aa6084: docs: Comprehensive README overhaul addressing user feedback.
Added a Prerequisites section prior to the Quick Start to highlight the optional
gclouddependency. Expanded the Authentication section with a decision matrix to help users choose the correct authentication path. Added prominent warnings about OAuth "testing mode" limitations (the 25-scope cap) and the strict requirement to explicitly add the authorizing account as a "Test user" (#130). Added a dedicated Troubleshooting section detailing fixes for common OAuth consent errors, "Access blocked" issues, andredirect_uri_mismatchfailures. Included shell escaping examples for Google Sheets A1 notation (!). Clarified thenpminstallation rationale and added explicit links to pre-built native binaries on GitHub Releases.
-
d3e90e4: fix: use ~/.config/gws on all platforms for consistent config path
Previously used
dirs::config_dir()which resolves to different paths per OS (e.g. ~/Library/Application Support/gws on macOS, %APPDATA%\gws on Windows), contradicting the documented ~/.config/gws/ path. Now uses ~/.config/gws/ everywhere with a fallback to the legacy OS-specific path for existing installs.
-
dbda001: Add "Enter project ID manually" option to project picker in
gws auth setup.Users with large numbers of GCP projects often hit the 10-second listing timeout. The picker now includes a "⌨ Enter project ID manually" item so users can type a known project ID directly without waiting for
gcloud projects listto complete.
-
87e4bb1: Add Linux ARM64 build targets (aarch64-unknown-linux-gnu and aarch64-unknown-linux-musl) to cargo-dist, enabling prebuilt binaries for ARM64 Linux users via npm, the shell installer, and GitHub Releases.
-
d1825f9: ### Multi-Account Support
Add support for managing multiple Google accounts with per-account credential storage.
New features:
--account EMAILglobal flag available on every commandGOOGLE_WORKSPACE_CLI_ACCOUNTenvironment variable as fallbackgws auth login --account EMAIL— associates credentials with a specific accountgws auth list— lists all registered accountsgws auth default EMAIL— sets the default accountgws auth logout --account EMAIL— removes a specific accountlogin_hintin OAuth URL for automatic account pre-selection in browser- Email validation via Google userinfo endpoint after OAuth flow
Breaking change: Existing users must run
gws auth loginagain after upgrading. The credential storage format has changed from a singlecredentials.encto per-account files (credentials.<b64-email>.enc) with anaccounts.jsonregistry.
-
a6994ad: Filter out
apps.alertsscopes from user OAuth login flow since they require service account with domain-wide delegation -
1ad4f34: fix: replace unwrap() calls with proper error handling in MCP server
Replaced four
unwrap()calls inmcp_server.rsthat could panic the MCP server process with graceful error handling. Also added a warning log when authentication silently falls back to unauthenticated mode. -
a1be14f: fix: drain stdout pipe to prevent project listing timeout during auth setup
Fixed
gws auth setuptiming out at step 3 (GCP project selection) for users with many projects. Thegcloud projects liststdout pipe was only read after the child process exited, causing a deadlock when output exceeded the OS pipe buffer (~64 KB). Stdout is now drained in a background thread to prevent the pipe from filling up. -
364542b: fix: reject DEL character (0x7F) in input validation
The
reject_control_charshelper rejected bytes 0x00–0x1F but allowed the DEL character (0x7F), which is also an ASCII control character. This could allow malformed input from LLM agents to bypass validation. -
75cec1b: Fix URL template expansion so media upload endpoints substitute path parameters and avoid iterative replacement side effects.
-
ed409e3: Harden URL and path construction across helper modules (gmail/watch, modelarmor, discovery)
-
263a8e5: fix: use gcloud.cmd on Windows and show platform-correct config paths
On Windows, gcloud is installed as
gcloud.cmdwhich Rust'sCommandcannot find without the extension. Also replaced hardcoded~/.config/gws/in error messages with the actual platform-resolved path.
-
4bca693: fix: credential masking panic and silent token write errors
Fixed
gws auth exportmasking which panicked on short strings and showed the entire secret instead of masking it. Also fixed silent token cache write failures insave_to_diskthat returnedOk(())even when the write failed. -
f84ce37: Fix URL template path expansion to safely encode path parameters, including Sheets
rangevalues with Unicode and reserved characters.{var}expansions now encode as a path segment,{+var}preserves slashes while encoding each segment, and invalid path parameter/template mismatches fail fast. -
eb0347a: fix: correct author email typo in package.json
-
70d0cdd: Fix Slides presentations.get failure caused by flatPath placeholder mismatch
When a Discovery Document's
flatPathuses placeholder names that don't match the method's parameter names (e.g.,{presentationsId}vspresentationId),build_urlnow falls back to thepathfield which uses RFC 6570 operators that resolve correctly.Fixes #118
-
37ab483: Add flake.nix for nix & NixOS installs
-
1991d53: Add prominent disclaimer that this is not an officially supported Google product to README, --help, and --version output
-
704928b: fix(setup): enable APIs individually and surface gcloud errors
Previously
gws auth setupused a single batchgcloud services enablecall for all Workspace APIs. If any one API failed, the entire batch was marked as failed and stderr was silently discarded. APIs are now enabled individually and in parallel, with error messages surfaced to the user.
- 92e66a3: Add
gws versionas a bare subcommand alongsidegws --versionandgws -V
- 8fadbd6: Smarter truncation of method and resource descriptions from discovery docs. Descriptions now truncate at sentence boundaries when possible, fall back to word boundaries with an ellipsis, and strip markdown links to reclaim character budget. Fixes #64.
- b3669e0: Add hourly cron to generate-skills workflow to auto-sync skills with upstream Google Discovery API changes via PR
- e8d533e: Add workflow to publish OpenClaw skills to ClawHub
- 3b38c8d: Sync generated skills with latest Google Discovery API specs
-
670267f: feat: add
gws mcpModel Context Protocol serverAdds a new
gws mcpsubcommand that starts an MCP server over stdio, exposing Google Workspace APIs as structured tools to any MCP-compatible client (Claude Desktop, Gemini CLI, VS Code, etc.).
- 8c1042a: Fix x-goog-api-client header format to use
gl-rust/gws-<version> - 3de9762: Fix docs:
gws setup→gws auth setup(fixes #56, #57)
-
f281797: docs(auth): add manual Google Cloud OAuth client setup and browser-assisted login guidance
Adds step-by-step guidance for creating a Desktop OAuth client in Google Cloud Console, where to place
client_secret.json, and how humans/agents can complete browser consent (including unverified app and scope-selection prompts). -
ee2e216: Narrow default OAuth scopes to avoid
Error 403: restricted_clienton unverified apps and add a--fullflag for broader access (fixes #25). Replace the cryptic non-interactive setup error with actionable step-by-step OAuth console instructions (fixes #24). -
de2787e: feat(error): detect disabled APIs and guide users to enable them
When the Google API returns a 403
accessNotConfigurederror (i.e., the required API has not been enabled for the GCP project),gwsnow:- Extracts the GCP Console enable URL from the error message body.
- Prints the original error JSON to stdout (machine-readable, unchanged shape
except for an optional new
enable_urlfield added to the error object). - Prints a human-readable hint with the direct enable URL to stderr, along with instructions to retry after enabling.
This prevents a dead-end experience where users see a raw 403 JSON blob with no guidance. The JSON output is backward-compatible; only an optional
enable_urlfield is added when the URL is parseable from the message.Fixes #31
-
9935dde: ci: auto-generate and commit skills on PR branch pushes
-
4b868c7: docs: add community guidance to gws-shared skill and gws --help output
Encourages agents and users to star the repository and directs bug reports and feature requests to GitHub Issues, with guidance to check for existing issues before opening new ones.
-
0603bce: fix: atomic credential file writes to prevent corruption on crash or Ctrl-C
-
666f9a8: fix(auth): support --help / -h flag on auth subcommand
-
bcd2401: fix: flatten nested objects in table output and fix multi-byte char truncation panic
-
ee35e4a: fix: warn to stderr when unknown --format value is provided
-
e094b02: fix: YAML block scalar for strings with
#/:, and repeated CSV/table headers with--page-allBug 1 — YAML output:
drive#filerendered as block scalarStrings containing
#or:(e.g.drive#file,https://…) were incorrectly emitted as YAML block scalars (|), producing output like:kind: | drive#file
Block scalars add an implicit trailing newline which changes the string value and produces invalid-looking output. The fix restricts block scalar to strings that genuinely contain newlines; all other strings are double-quoted, which is safe for any character sequence.
Bug 2 —
--page-allwith--format csv/--format tablerepeats headersWhen paginating with
--page-all, each page printed its own header row, making the combined output unusable for downstream processing:id,kind,name ← page 1 header 1,drive#file,foo.txt id,kind,name ← page 2 header (unexpected!) 2,drive#file,bar.txtColumn headers (and the table separator line) are now emitted only for the first page; continuation pages contain data rows only.
-
173d155: fix: add YAML document separators (---) when paginating with --page-all --format yaml
-
214fc18: ci: skip smoketest on fork pull requests
-
6ae7427: fix(auth): stabilize encrypted credential key fallback across sessions
When the OS keyring returned
NoEntry, the previous code could generate a fresh random key on each process invocation instead of reusing one. This causedcredentials.encwritten bygws auth loginto be unreadable by subsequent commands.Changes:
- Always prefer an existing
.encryption_keyfile before generating a new key - When generating a new key, persist it to
.encryption_keyas a stable fallback - Best-effort write new keys into the keyring as well
- Fix
OnceLockrace: return the already-cached key ifsetloses a race
Fixes #27
- Always prefer an existing
-
b0d0b95: Add workflow helpers, personas, and 50 consumer-focused recipes
- Add
gws workflowsubcommand with 5 built-in helpers:+standup-report,+meeting-prep,+email-to-task,+weekly-digest,+file-announce - Add 10 agent personas (exec-assistant, project-manager, sales-ops, etc.) with curated skill sets
- Add
docs/skills.mdskills index andregistry/recipes.yamlwith 50 multi-step recipes for Gmail, Drive, Docs, Calendar, and Sheets - Update README with skills index link and accurate skill count
- Fix lefthook pre-commit to run fmt and clippy sequentially
- Add
-
90adcb4: fix: percent-encode path parameters to prevent path traversal
-
e71ce29: Fix Gemini extension installation issue by removing redundant authentication settings and update the documentation.
-
90adcb4: fix: harden input validation for AI/LLM callers
- Add
src/validate.rswithvalidate_safe_output_dir,validate_msg_format, andvalidate_safe_dir_pathhelpers - Validate
--output-diragainst path traversal ingmail +watchandevents +subscribe - Validate
--msg-formatagainst allowlist (full, metadata, minimal, raw) ingmail +watch - Validate
--diragainst path traversal inscript +push - Add clap
value_parserconstraint for--msg-format - Document input validation patterns in
AGENTS.md
- Add
-
90adcb4: Security: Harden validate_resource_name and fix Gmail watch path traversal
-
90adcb4: Replace manual
urlencoded()with reqwest.query()builder for safer URL encoding -
c11d3c4: Added test coverage for
EncryptedTokenStorage::newinitialization. -
7664357: Add test for missing error path in load_client_config
-
90adcb4: fix: add shared URL safety helpers for path params (
encode_path_segment,validate_resource_name) -
90adcb4: fix: warn on stderr when API calls fail silently
- d29f41e: Fix README typography and spacing
- adb2cfa: Fix OAuth login failing with "no refresh token" error by decrypting the token cache before parsing and supporting the HashMap token format used by EncryptedTokenStorage
- d990dcc: Improve README branding by making the hero banner full-width.
- c714f4b: Fix npm package name to publish as @googleworkspace/cli instead of gws
- 3cd4d52: Fix release pipeline to sync Cargo.toml version with changesets and create git tags for private packages
- a0ad089: Speed up CI builds with Swatinem/rust-cache, sccache, and build artifact reuse for smoketests
- 30d929b: Optimize demo GIF and improve README