npm.io
0.16.2 • Published 20h agoCLI

gws-axi

Licence
MIT
Version
0.16.2
Deps
7
Size
1.1 MB
Vulns
0
Weekly
0
Stars
6

gws-axi

Agent-ergonomic CLI for Google Workspace — Gmail, Calendar, Docs, Drive, Slides, and Sheets behind a single command, built to the AXI standard: TOON-formatted output, contextual next-step suggestions, idempotent mutations, and multi-account safety by default.

Designed for use by AI agents. Every response is structured, every error names a specific fix, and write operations lock to the explicit account when multiple are authenticated — so two agents in parallel sessions can't silently touch the wrong mailbox.

Status

Read coverage is complete across all six services; write coverage is rolling out service by service.

Service Reads Writes
Calendar events · get · calendars · search · freebusy create · update · delete · respond
Gmail search · read · labels · download triage · draft · labels · filters  ·  send out of scope
Docs read · find · comments · download · revisions · diff append · insert-text · delete-range
Drive ls · get · search · permissions · download · revisions · activity upload · mkdir  ·  create · copy · move · rename · delete
Slides get · page · summarize · comments create · update
Sheets read · comments update · append · clear · create · add-tab

shipped · partial · planned · out of scope by design

Auth (including the single-developer auth publish walkthrough that retires the 7-day Testing-token expiry), doctor with live per-account API probes, and multi-account write-protection are stable. Gmail send is intentionally out of scope — gws-axi drafts mail for human review but never sends it.

Requirements

  • Node.js ≥ 20
  • A Google account (personal or Workspace)
  • gcloud CLI (optional — speeds up initial setup, not required)

Getting started

1. Install
npm install -g gws-axi
2. Let an agent walk you through setup

gws-axi is designed to be driven by an AI coding agent (Claude Code, Cursor, anything that can run shell commands). The setup flow is progressive — the CLI emits structured TOON output telling the agent what to do next, and the agent coordinates with you through the handful of Google Cloud Console steps that can't be automated.

Start a fresh agent session and paste a prompt like:

Run `gws-axi auth setup` and walk me through the progressive setup
flow it describes. The CLI's output will tell you exactly what to do
at each step — relay the instructions to me, and run follow-up
commands as you go.

I want to authenticate the following Google accounts:
  - you@example.com
  - personal@gmail.com

The explicit gws-axi auth setup in the prompt matters: this is your very first session, so the agent doesn't yet have any ambient context about gws-axi. Naming the first command gets the agent into the structured flow, where the CLI's output takes over. Once you install the SessionStart hook (see step 4), every subsequent session auto-loads a compact gws-axi status line — so after that, you can skip the command and just say "use gws-axi to ..." and the agent knows.

Expect ~10 minutes end-to-end for a fresh Google Cloud project; ~3 minutes if you already have one you want to reuse.

What happens during setup: you create your own Google Cloud project with OAuth credentials, enable the Workspace APIs, configure the consent screen, and add your Google accounts as test users. This is the bring-your-own OAuth client model — avoids public-app verification overhead and keeps the blast radius of any token revocation scoped to you. Tokens live locally at ~/.config/gws-axi/.

The CLI generates an auto-refreshing HTML helper page (~/.config/gws-axi/setup.html) with clickable Console deep-links — so you never copy long URLs from terminal to browser and you stay in the right browser profile throughout.

3. Check it works
gws-axi doctor                           # setup + live API health
gws-axi calendar events                  # upcoming 7 days on your primary calendar
4. Make gws-axi your agent's default for Google Workspace

gws-axi gives agents two complementary ways to pick up ambient context (per AXI principle 7 — context is delivered through hooks and installable skills, and installation is always explicit opt-in, never a side effect of ordinary commands):

gws-axi setup hooks

This installs a SessionStart hook into your agent's config — Claude Code (~/.claude/settings.json), Codex (~/.codex/hooks.json), and OpenCode. From then on, every new agent session sees a compact gws-axi status line in ambient context — authenticated accounts, write-protection status, setup health. The command is idempotent and self-repairing: re-run it any time (e.g. after upgrading or moving the install) and it repairs a stale executable path without duplicating entries. There is no auto-install — the hook only appears when you run setup hooks.

The hook and an installable skill are the two ambient-context paths: the hook injects current state at session start, while a skill can teach the agent the full command surface on demand. Run gws-axi setup hooks to get the hook in place.

To make sure agents reach for gws-axi instead of stale alternatives, also consider:

  • Remove existing Google Workspace MCP servers and skills. If you already have Gmail / Calendar / Drive / Docs / Slides integrations installed (community MCP servers, bespoke skills, etc.), disable them. Keeping both creates ambiguity — agents may pick whichever they noticed first, and the tools have different auth models, flag names, and output shapes. Typical candidates to disable: google-calendar-mcp, gmail-mcp, google-docs-mcp, any @modelcontextprotocol/server-google-*, and skills with similar names.

  • Add a directive to your CLAUDE.md. A short note in your project-level (.claude/CLAUDE.md) or user-level (~/.claude/CLAUDE.md) file nudges agents to consistently use gws-axi. Example:

    ## Google Workspace
    
    Use `gws-axi` for ALL Google Calendar, Gmail, Docs, Drive, Slides, and Sheets
    interactions. Check the SessionStart `gws-axi` line for current auth
    state; run `gws-axi --help` for the command surface. Prefer this over
    any other Google integrations.
Prefer to drive it manually?

The CLI works fine without an agent — each gws-axi auth setup invocation prints its own instructions and updates setup.html. Run it repeatedly as you complete each step; no state is lost between invocations.

Usage

Every subcommand supports --help. The bare gws-axi command prints current state, authenticated accounts, and top suggestions.

Home / auth / health
gws-axi                                  # home view — current state + suggestions
gws-axi auth accounts                    # list authenticated Google accounts
gws-axi auth login --account <email>     # add another account (blocks on callback)
gws-axi auth login --account <email> --no-wait  # agent-friendly split: prepare now, run --wait separately
gws-axi auth publish                     # walk Testing → Production to retire 7-day token expiry
gws-axi auth use <email>                 # set the default account
gws-axi doctor                           # prerequisites + setup + live API probes
Calendar reads
gws-axi calendar events                  # upcoming 7 days on primary
gws-axi calendar events --from 2026-04-20T00:00 --to 2026-04-27T00:00
gws-axi calendar events --fields attendees,location,status
gws-axi calendar get <event-id>          # full detail + attendees
gws-axi calendar get <event-id> --full   # don't truncate description
gws-axi calendar calendars               # list calendars accessible to this account
gws-axi calendar search --query "standup"  # primary calendar by default
gws-axi calendar search --query "chris" --include-shared  # include delegated + subscribed
gws-axi calendar freebusy --calendars primary,team@jarv.us  # cross-calendar availability
Calendar writes
gws-axi calendar create \
  --summary "Team sync" --start 2026-04-22T14:00 --duration 30m

gws-axi calendar update <event-id> \
  --summary "Team sync (rescheduled)" --start 2026-04-22T15:00

gws-axi calendar delete <event-id>       # idempotent (404/410 → noop)

gws-axi calendar respond <event-id> --response accepted

Writes default --send-updates to none so agent-created events don't spam attendees. Pass --send-updates all for production-style invite behavior.

Gmail

Reads:

gws-axi gmail search                              # in:inbox by default
gws-axi gmail search --query "from:alice has:attachment"
gws-axi gmail search --page <token>               # paginate
gws-axi gmail read <thread-or-message-id>         # whole thread, text/plain preferred
gws-axi gmail read <id> --message-only            # just one message
gws-axi gmail read <id> --out ./thread.md         # write the full thread to a markdown file
gws-axi gmail labels                              # list labels with IDs
gws-axi gmail download <message-id> <attachment-id>  # fetch attachment bytes

Writes (triage, drafting, labels, filters — but never send):

# Triage — Gmail state IS labels, so archive/read/star are label edits:
gws-axi gmail modify <message-id> --remove-label INBOX        # archive
gws-axi gmail modify <message-id> --remove-label UNREAD       # mark read
gws-axi gmail modify <message-id> --add-label STARRED         # star
gws-axi gmail modify <message-id> --add-label "Work/Clients" --remove-label INBOX
gws-axi gmail modify <thread-id> --thread --remove-label UNREAD  # whole thread

# Bulk triage by query:
gws-axi gmail batch-modify --query "from:news@x.com" --remove-label INBOX
gws-axi gmail batch-modify --query "is:unread older_than:30d" --remove-label UNREAD

# Drafts (composed for you; you send from Gmail):
gws-axi gmail draft --to alice@x.com --subject "Re: budget" --body "Approved."
gws-axi gmail draft --to a@x.com,b@x.com --subject Hi --body-file ./note.txt --thread <id>

# Label management:
gws-axi gmail label-create --name "Work/Clients"
gws-axi gmail label-update <label-id|name> --name "Archive"
gws-axi gmail label-delete <label-id|name>

# Server-side auto-sort filters:
gws-axi gmail filter-list
gws-axi gmail filter-create --from news@x.com --remove-label INBOX --add-label News
gws-axi gmail filter-delete <filter-id>

Bodies are decoded per declared Content-Type charset (UTF-8, latin-1, ascii, utf-16). HTML-only messages convert to markdown via turndown. Address headers parse with addressparser so display names with commas don't get split.

On send: gws-axi has no send command by design — an agent can triage, label, and draft replies, but a human reviews and sends from Gmail. This is a guardrail against accidental sends, not a hard security boundary (the OAuth token is send-capable; there is no Gmail scope that grants drafting + label edits while withholding send). gws-axi gmail send returns a NOT_SUPPORTED error pointing at draft.

Scope note: the filter commands need the gmail.settings.basic scope, which gmail.modify does not include. Accounts authenticated before this release will get a SCOPE_MISSING (403) on filter commands until you re-run gws-axi auth login --account <email> once to re-consent.

Docs
gws-axi docs read <documentId>                    # full Doc as markdown (+ recent revisions inline)
gws-axi docs read <documentId> --out ./doc.md     # write to a file
gws-axi docs find <documentId> --query "deadline" # search inside one Doc
gws-axi docs comments <documentId>                # threaded comments + suggestions
gws-axi docs revisions <documentId>               # version history (id, modified, author)
gws-axi docs diff <documentId> <revA> [revB]      # unified diff between two revisions (revB defaults to head)
gws-axi docs download <documentId> --as application/pdf   # native export (pdf, docx, odt, txt, html, epub, rtf)
gws-axi docs download <documentId> --revision <id>        # fetch a past revision's content (markdown by default)

Every docs read carries the document's recent revisions and points at docs revisions / docs download --revision / docs diff — so an agent always knows which version it read. Non-native files (uploaded .docx, .pdf, etc.) get pointed at docs download automatically rather than failing with a cryptic Google API error.

Drive

Reads:

gws-axi drive ls                                  # top of My Drive
gws-axi drive ls <folder-id> --recursive          # depth-unbounded; bounded by --limit instead
gws-axi drive get <fileId>                        # metadata for one file
gws-axi drive search --query "name contains 'budget'"
gws-axi drive permissions <fileId>                # who has access
gws-axi drive revisions <fileId>                  # version history (any file type)
gws-axi drive activity <itemId>                   # attributed change timeline (Drive Activity API)
gws-axi drive download <fileId> --out ./file      # fetch bytes / export a native file

Writes:

gws-axi drive mkdir "Reports" --account you@example.com         # create a folder
gws-axi drive upload ./report.pdf --account you@example.com     # upload a local file
echo '# Notes' | gws-axi drive upload - --name notes.md --convert --account you@example.com   # stdin → native Doc
gws-axi drive upload --content '# Notes' --name notes.md --convert --account you@example.com   # inline content → native Doc
gws-axi drive upload ./edited.md --convert --update <docId> --account you@example.com          # replace a Doc's content (new revision)

drive upload takes content from a local path, - (stdin), or --content; --convert imports it into the matching native Google format. With --update it replaces an existing file's content — and when that file is already the matching native type, --convert --update writes edited markdown back into the same Doc as a new revision.

Slides
gws-axi slides get <presentationId>               # deck metadata + slide list
gws-axi slides page <presentationId> <slideId>    # one slide's content
gws-axi slides summarize <presentationId>         # all slides condensed to text per slide
gws-axi slides comments <presentationId>          # review comments (Drive comments)

Embedded hyperlinks in slide text resolve inline as markdown [text](url) (with links_resolved: N in the header); images/videos are counted, not inlined.

Sheets

A spreadsheet's tabs are its sheets, so sheets read mirrors docs read: it lists the tabs, and renders one tab's grid into context. Embedded links resolve inline as markdown [text](url); cell notes come back in a notes[] block.

gws-axi sheets read <spreadsheetId>                       # single tab renders; multi-tab lists tabs to pick
gws-axi sheets read <spreadsheetId> --tab Costs           # by tab title (or numeric gid)
gws-axi sheets read <spreadsheetId> --tab Costs --range A1:D50   # scope to an A1 range
gws-axi sheets read <spreadsheetId> --header-row          # promote row 1 to column names (auto for a frozen top row; --raw to force letters)
gws-axi sheets read <spreadsheetId> --tab Costs --full    # don't cap at 50 rows
gws-axi sheets comments <spreadsheetId>                   # review comments (Drive comments)

Cell values are the displayed strings (not formulas). The new spreadsheets scope means existing accounts must gws-axi auth login once.

Multi-account with write protection

gws-axi supports multiple Google accounts under one OAuth client. When two or more are authenticated, write operations require --account <email> explicitly — silent wrong-account mutations are impossible:

gws-axi calendar events                         # read: uses default account
gws-axi calendar create --summary "..."         # write: ACCOUNT_REQUIRED error
gws-axi calendar create --account chris@jarv.us --summary "..."  # OK
Example output
account: chris@jarv.us
count: 3
range: 2026-04-20T14:00:00.000Z → 2026-04-27T14:00:00.000Z
events[3]{id,summary,start,end,my_response}:
  abc123,Team standup,2026-04-21T14:00:00-04:00,2026-04-21T14:15:00-04:00,accepted
  def456,1:1 with Ari,2026-04-22T15:30:00-04:00,2026-04-22T16:00:00-04:00,accepted
  ghi789,Board meeting,2026-04-25,2026-04-26,needsAction
help[2]:
  Run `gws-axi calendar get <id>` for full event details
  Add `--fields attendees,location,status` to show more columns

Design docs

Known issues & roadmap

  • Gmail send: intentionally unsupported — gws-axi drafts mail but leaves sending to a human in the Gmail UI. See the Gmail section above.
  • Docs writes (append, insert-text, delete-range, etc.): scaffolded as NOT_IMPLEMENTED. The next frontier.
  • Drive writes: upload and mkdir are shipped; create / copy / move / rename / delete are still scaffolded as NOT_IMPLEMENTED.
  • Slides writes: still scaffolded as NOT_IMPLEMENTED (reads are complete).
  • Sheets writes (update, append, clear, create, add-tab): scaffolded as NOT_IMPLEMENTED; read (with inline-markdown links + cell notes) and comments are shipped.
  • Testing-mode tokens still expire every 7 days if you haven't published your OAuth app yet. Run gws-axi auth publish for the walkthrough — it covers the single-developer Production flow and removes the expiry once you've re-auth'd each account.

Contributing

Issues and PRs welcome at github.com/JarvusInnovations/gws-axi.

License

MIT — see LICENSE.

Keywords