skill / google-chat
!

Not installable via adompkg

This skill has no published release. adompkg install kyle/google-chat will not work until a maintainer publishes a tarball with install.sh and uninstall.sh.

See the publishing docs for the package.json schema and tarball layout required to ship this skill.


name: google-chat
description: Use when the user wants to send Google Chat messages, list Chat spaces, manage the Chat poller, check Chat connectivity, or troubleshoot Google Chat integration. Covers MCP tools for messaging, space management, OAuth setup, and the poller that auto-responds to DMs and @mentions.

Google Chat

Your Gallia workspace includes a Google Chat integration that lets you send and receive messages through the Google Chat REST API. A bot user in your Google Workspace authenticates via OAuth and can auto-respond to DMs and @mentions using Claude Code.

Setup (New Installation)

1. Create a Google Cloud Project

  1. Go to Google Cloud Console and create a new project
  2. Enable the Google Chat API (APIs & Services > Library > search "Google Chat API")
  3. Go to APIs & Services > Credentials > Create Credentials > OAuth 2.0 Client ID
  4. Application type: Web application
  5. Add an authorized redirect URI: https://<your-gallia-url>/proxy/3456/callback
  6. Save the Client ID and Client Secret

2. Create a Bot User Account

Create a user in your Google Workspace Admin console (e.g., [email protected]). This user will be the "face" of your AI assistant in Google Chat. Other users will DM this account or @mention it in spaces.

3. Initialize OAuth Credentials

Create the config file with your OAuth credentials:

mkdir -p ~/.config
cat > ~/.config/gchat-oauth.json << 'EOF'
{
  "clientId": "<your-client-id>",
  "clientSecret": "<your-client-secret>",
  "redirectUri": "https://<your-gallia-url>/proxy/3456/callback"
}
EOF

Then run the login flow:

cd ~/gallia/gchat && node oauth-login.js

Visit the URL it prints, log in as your bot account, and click Allow. The refresh token is saved automatically.

4. Configure Bot Identity (Optional)

Create a .env file to customize the bot's behavior:

cat > ~/gallia/gchat/.env << 'EOF'
GCHAT_BOT_NAME=MyBot
GCHAT_SYSTEM_PROMPT=You are MyBot, an AI assistant responding in Google Chat. Keep responses concise.
CLAUDE_WORK_DIR=/home/adom/project
EOF

See gchat/.env.example for all available environment variables.

5. Start the Poller

cd ~/gallia/gchat && node poller.js

Or in background:

cd ~/gallia/gchat && nohup node poller.js > /tmp/gchat-poller.log 2>&1 &

6. Verify in Gallia Viewer

Open the Google Chat view in Gallia Viewer (Tools > Google Chat). The health bar should show "Connected" with your space count. Try sending a test message to verify everything works.

Architecture

Google Chat <-> Chat REST API (OAuth) <-> Poller (node poller.js) <-> Claude Code CLI
                                     <-> MCP Tools (adom-gchat)   <-> Claude Code session

Two operational modes:

  • Poller (primary) — poller.js polls all spaces every 5s, detects new messages, spawns Claude Code, sends responses
  • MCP tools (interactive) — Claude Code sends messages on-demand via gchat_send_message, gchat_send_card, etc.

Available MCP Tools

All tools are registered under the adom-gchat MCP server.

gchat_send_message — Send a Message

Send a text message to any Google Chat space.

Parameter Type Description
space string Space resource name (e.g. "spaces/AAAA1234") for Chat API, or webhook space name (e.g. "general") for legacy webhooks
text string Message text. Supports Google Chat formatting: *bold*, _italic_, ~strikethrough~, `code`, triple backticks
threadKey string? Optional thread key for threading messages

gchat_send_card — Send a Rich Card

Send a structured card message with headers, sections, and widgets.

Parameter Type Description
space string Space resource name or webhook space name
card object Card v2 object with header, sections, widgets
fallbackText string? Plain text shown in notifications
threadKey string? Optional thread key

gchat_list_spaces — List Spaces

Lists all Google Chat spaces the bot has access to. Shows both Chat API spaces (where the bot is a member) and legacy webhook spaces.

gchat_add_space — Register Webhook Space

Register a legacy webhook URL for a space. Not needed for spaces where the bot is already a member — use the space name from gchat_list_spaces instead.

Parameter Type Description
name string Short name for the space (e.g. "general", "eng")
webhookUrl string Full webhook URL from Google Chat (starts with https://chat.googleapis.com/)

gchat_remove_space — Remove Webhook Space

Remove a configured webhook space by name.

gchat_health — Check Connectivity

Check Google Chat connectivity: OAuth token status, Chat API reachability, and webhook configuration.

Message Flow (Poller)

When the poller detects a new message:

  1. Detect — Poll listMessages with orderBy=createTime desc to get newest messages first
  2. Filter — Skip the bot's own messages. In DMs, process all human messages. In groups, require @mention.
  3. Thinking — Send "On it, {name}..." placeholder message
  4. Heartbeat — Update thinking message every 30s with elapsed time while Claude works
  5. Respond — Update thinking message to "Done in {time}", send Claude's response as a new message (triggers unread indicator)
  6. Error — If Claude fails, send an error message with details

Configuration

Environment Variables

All configuration is via environment variables, set in ~/gallia/gchat/.env or exported in your shell. See .env.example for the full list.

Variable Default Description
GCHAT_CONFIG_PATH ~/.config/gchat-oauth.json OAuth credentials file
GCHAT_WEBHOOKS_PATH ~/.config/gchat-webhooks.json Legacy webhook config
GCHAT_STATE_PATH ~/.config/gchat-poller-state.json Poller state file
GCHAT_BOT_NAME Bot Display name for @mention matching and logs
GCHAT_BOT_USER_ID (auto-match) Google user ID for the bot (optional)
GCHAT_SYSTEM_PROMPT Generic assistant prompt System prompt for Claude
GCHAT_POLL_INTERVAL 5000 Poll interval in ms
CLAUDE_BIN claude Path to Claude CLI
CLAUDE_WORK_DIR cwd Working directory for Claude
OAUTH_REDIRECT_URL http://localhost:3456/ OAuth redirect URL for login flow

OAuth Credentials

File: ~/.config/gchat-oauth.json (or GCHAT_CONFIG_PATH)

Contains clientId, clientSecret, refreshToken, accessToken, expiresAt. Tokens auto-refresh when expired.

OAuth scopes: chat.messages, chat.messages.create, chat.spaces, chat.spaces.readonly, chat.memberships, chat.memberships.readonly

Webhook Config (Legacy)

File: ~/.config/gchat-webhooks.json (or GCHAT_WEBHOOKS_PATH)

Legacy webhook URLs for spaces. Used by MCP tools as a fallback when the bot isn't a member of a space. Register webhooks via gchat_add_space or manually edit the file.

Poller State

File: ~/.config/gchat-poller-state.json (or GCHAT_STATE_PATH)

Tracks lastSeen timestamp per space and caches user display names. The poller initializes new spaces to "now" to avoid processing old messages on first start.

DM Acceptance Requirement

When someone DMs the bot for the first time, that DM must be "accepted" before the bot can reply:

  • Bot initiating: Use spaces:setup API — the recipient must accept in Google Chat UI
  • User initiating: The bot must accept the DM in Google Chat UI (log in as the bot account)
  • Without acceptance: API can read messages but cannot send (403 error)
  • After acceptance: Full read/write works permanently

Claude Code Integration

  • Claude CLI path: configurable via CLAUDE_BIN env var
  • Working directory: configurable via CLAUDE_WORK_DIR env var
  • Must unset CLAUDECODE env var when spawning (avoids nested detection)
  • Uses script -qc for pseudo-TTY (required by Claude CLI)
  • ANSI escape codes are stripped from output
  • Response truncated to 4000 chars (Google Chat limit)

Google Chat Formatting

*bold*  _italic_  ~strikethrough~  `code`  ```code block```

Troubleshooting

Bot doesn't respond to new messages

  1. Check the poller is running: pgrep -f 'node poller'
  2. Check poller logs: tail -f /tmp/gchat-poller.log
  3. Verify OAuth tokens: use gchat_health MCP tool
  4. For new DM spaces — the poller refreshes spaces every ~5 min, or restart the poller

403 error on DMs

The DM hasn't been accepted yet. Log into Google Chat as the bot account and accept the DM, or have the bot initiate the DM via spaces:setup.

Messages detected but Claude errors

  • Check for "Session ID already in use" — should be fixed with --no-session-persistence
  • Check Claude CLI is installed and on PATH (or set CLAUDE_BIN)
  • Check CLAUDECODE env var is being unset in the spawned process

Old messages being re-processed

The poller uses orderBy=createTime desc to fetch newest messages first. If old messages are being processed, the lastSeen timestamp in the poller state file may be stale. Delete the state file and restart the poller.

Files

File Purpose
gchat/chat-api.js Google Chat REST API client with OAuth token auto-refresh
gchat/poller.js Main polling loop — detects messages, spawns Claude, sends responses
gchat/claude-runner.js Spawns Claude Code CLI via script -qc PTY wrapper, strips ANSI
gchat/server.js Legacy webhook HTTP server on port 8780
gchat/oauth-login.js One-time OAuth login flow (port 3456)
gchat/load-env.js Minimal .env file loader (no dependencies)
gchat/mcp/server.js MCP stdio transport entry point
gchat/mcp/tools.js MCP tool definitions (6 tools)
gchat/.env.example Template for environment variables