Install this skill

Paste this into Claude Code (VS Code panel, Adom editor, or terminal) to install:

Search the Adom Wiki for the skill "Google Chat" (slug: google-chat) at https://wiki-ufypy5dpx93o.adom.cloud/wiki/skills/google-chat and install it into my local ~/.claude/skills/google-chat/ directory. Fetch the skill_source content from the wiki page and save it as SKILL.md. Then confirm it's installed by showing the first 5 lines.
?
What is a skill? Skills are instructions that teach AI assistants like Claude Code how to perform specific tasks. The description below is loaded into the AI as context when you invoke this skill. Well-written skills make the AI significantly more effective. Like Wikipedia, anyone can improve a skill by clicking Edit AI Skill — or have your AI submit an edit on your behalf.

Description

Edit AI 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.

ParameterTypeDescription
spacestringSpace resource name (e.g. "spaces/AAAA1234") for Chat API, or webhook space name (e.g. "general") for legacy webhooks
textstringMessage text. Supports Google Chat formatting: *bold*, _italic_, ~strikethrough~, `code`, triple backticks
threadKeystring?Optional thread key for threading messages

gchat_send_card — Send a Rich Card

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

ParameterTypeDescription
spacestringSpace resource name or webhook space name
cardobjectCard v2 object with header, sections, widgets
fallbackTextstring?Plain text shown in notifications
threadKeystring?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.

ParameterTypeDescription
namestringShort name for the space (e.g. "general", "eng")
webhookUrlstringFull 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.

VariableDefaultDescription
GCHAT_CONFIG_PATH~/.config/gchat-oauth.jsonOAuth credentials file
GCHAT_WEBHOOKS_PATH~/.config/gchat-webhooks.jsonLegacy webhook config
GCHAT_STATE_PATH~/.config/gchat-poller-state.jsonPoller state file
GCHAT_BOT_NAMEBotDisplay name for @mention matching and logs
GCHAT_BOT_USER_ID(auto-match)Google user ID for the bot (optional)
GCHAT_SYSTEM_PROMPTGeneric assistant promptSystem prompt for Claude
GCHAT_POLL_INTERVAL5000Poll interval in ms
CLAUDE_BINclaudePath to Claude CLI
CLAUDE_WORK_DIRcwdWorking directory for Claude
OAUTH_REDIRECT_URLhttp://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

FilePurpose
gchat/chat-api.jsGoogle Chat REST API client with OAuth token auto-refresh
gchat/poller.jsMain polling loop — detects messages, spawns Claude, sends responses
gchat/claude-runner.jsSpawns Claude Code CLI via script -qc PTY wrapper, strips ANSI
gchat/server.jsLegacy webhook HTTP server on port 8780
gchat/oauth-login.jsOne-time OAuth login flow (port 3456)
gchat/load-env.jsMinimal .env file loader (no dependencies)
gchat/mcp/server.jsMCP stdio transport entry point
gchat/mcp/tools.jsMCP tool definitions (6 tools)
gchat/.env.exampleTemplate for environment variables

Skill Source

Edit AI 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](https://console.cloud.google.com/) 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:

```bash
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:

```bash
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:

```bash
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

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

Or in background:
```bash
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 |

Sub-Skills
?
What are Sub-Skills?

Sub-skills are community-contributed AI skill extensions for this component. They teach AI assistants about specific tools, configurators, or workflows.

Examples:

  • A manufacturer’s configuration tool for a motor controller
  • A community-written design guide for an amplifier circuit
  • An automated test/validation script for a sensor module

How to add one: Click Add Sub-Skill, provide the URL to your skill and a brief description. Submissions are reviewed by the Adom team before going live.

No sub-skills yet. Be the first to contribute one!

0 revisions · Updated 2026-03-02 17:31:35