Background: I gave up after 2-weeks, trying to set up OpenClaw on AWS VPS. I switched to Hermes AI Agent (from NousResearch). Its a personal AI assistant that works across WhatsApp, Slack & email etc. The promise is compelling: one agent that understands natural language, connects to your tools, and automates repetitive work. The reality of setting it up, however, involves a trail of confusing errors, conflicting documentation, and subtle gotchas that can eat days (and nights) of your time. This post is the guide I wish existed when I started. It’s based on a real, working production setup built on AWS, connecting WhatsApp and Slack to Google Sheets, Gmail, and custom Python scripts, and it covers every wrong turn along the way.
Objective
Eventual goal is to setup a personal AI Assistant that can automate your manual tasks & also grow to be your Chief of Staff. For now, the scope of this post is to get the basic Hermes setup working with Gmail, automation scripts & CRON jobs.

My hardware setup
- Macbook Air: Needed to authenticate with Google and generate OAuth credentials
- AWS EC2 (t3.medium running Ubuntu):
- Hermes runs here as a background service, 24/7, handling messages from WhatsApp and Slack, executing Python scripts, and calling Google APIs. (Do not install this on your daily computer (personal or work).
- You can setup SSH from your daily computer (which is complicated) or simply connect via EC2 Instance Connect from the AWS dashboard (simpler, works from everywhere).
Model Choices
There’s no one way to setup Hermes or any agent framework for that matter. There are two choices:
- Option A: WhatsApp → Hermes (LLM) → Reads Skill → Calls Python script → Google Sheet
- Token spend for: LLM understand the message, maps to a relevant skill
- Very token efficient
- Predictable behaviour; works every single time
- Small-medium model will suffice; does not require expensive models.
- Option B: WhatsApp → Hermes (LLM) → LLM writes AND executes gws command → Google Sheet
- Token spend for: LLM understands the message, generates the command every single time, run gws
- Depends on the quality of the underlying model (lite, vs regular vs pro models etc)
- Small models hallucinate; leads to unpredictable behaviour.
At the beginning I didn’t really understand this deeply. Chose gemini-2.5-flash-lite. Ended up wasting many hours debugging trying to understand why the Whatsapp prompt didn’t work. Once I understood how the underlying framework works, I switched to gemini-2.5-flash and prompts immediately started to work.
For more complex routing & decisioning, I might have to switch to Claude models. That’s for another post for another day.
Caution!
While I have attempted to capture all the steps as accurately as possible, I guarantee that you will run into dozens or hundreds of errors that you have to debug yourself. It ias not as straight forward as install a Windows or Max app. We are still in the early stages and these systems have many rough edges. But that’s what makes it fun, isn’t it?
I used Gemini as my companion to help debug. Most of the times I felt it led me astray and I ended up wasting time running in circles. Then I switched to Claude Pro using Sonnet 4.6 to help me debug errors and think through next steps. Claude Sonnet 4.6 is significantly better than Gemini 3 Fast/Thinking.
Hermes installation & setup
To install, use the Nous documentation, which is straight forward.
Slack & Whatsapp integration
Slack & Whatsapp integrations are straight forward. See slack and whatsapp documentation here.
GWS setup for Gmail, Calendar, Drive, Sheets etc)
- Getting this to work reliably was the most time consuming 🙄
- Native Hermes ⇔ GWS integration
- Very flaky when it comes to triggering from Whatsapp/Slack, CRON etc.
- Also regularly conflicts with Hermes ⇔ Himalaya email.
- Disable Hermes ⇔ GWS and related gmail, drive, sheets, triage etc.
- Install GWS for Linux
- Configure this to run independently via Terminal (not via Hermes). This works reliably & predictably whether it’s invoked via Hermes, Whatsapp/Slack channels or CRON jobs.
- Installing was easy, configuring was anything but 🥵. Configuring it on a Mac Mini would have been easier but doing so on a VPS without a browser was extremely painful (especially because I was doing it for the first time without any documentation).
- Step 1: On VPS, install GWS: using
npm install -g @googleworkspace/cli. - Step 2: On your local m/c, install GWS: using
npm install -g @googleworkspace/cli. - Step 3:
- Create a project on Google Cloud
- Enable APIs (Gmail, Calendar, Drive, Sheets, Docs, People etc)
- Step 4: GCloud authentication
- After multiple failed attempts via OAuth, I decided to switch to GCloud authentication
- If not already installed, install using
brew install --cask google-cloud-sdk - Verify client_id & client_secret exist in ~/.config/gws/client_secret.json
gcloud auth application-default login \--client-id-file=$HOME/.config/gws/client_secret.json \--scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.send,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/drive- This should open a browser. Make sure you are signed in to the email ID where you created the Google Cloud project. Approve all complete the steps.
- Save credentials to
~/.config/gcloud/application_default_credentials.json - Verify client_id, client_secret & refresh_token are ok & not truncated.
- Step 5: Transfer JSON to VPS
- On your local machine, convert to base64 before transferring
cat ~/.config/gcloud/application_default_credentials.json | base64 - On your VPS, in
~/gws-creds-b64.txt, copy above JSON contents - Decode the base64 file
base64 -d ~/gws-creds-b64.txt > ~/gws-credentials-manual.json rm ~/gws-creds-b64.txt chmod 600 ~/gws-credentials-manual.json - Verify against the values on local machine
cat ~/gws-credentials-manual.json | python3 -m json.tool
- On your local machine, convert to base64 before transferring
- Step 6: On your VPS, configure GWS to use this
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=$HOME/gws-credentials-manual.jsonecho 'export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=$HOME/gws-credentials-manual.json' >> ~/.bashrcunset GOOGLE_WORKSPACE_CLI_IMPERSONATED_USERsed -i '/GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER/d' ~/.bashrcsource ~/.bashrc
- Step 7: Test GWS is working
gws auth statusgws gmail list --params '{"userId": "me", "resource": "users/me/messages", "maxResults": 1}'gws gmail +triagegws gmail +send --to name@gmail.com --subject "test from gws" --body "Hello from the VPS"
Setup GWS global variable (IMPORTANT)
- Setup as global variable
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=$HOME/gws-credentials-manual.jsonecho $GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE # Verify it's set
- Persist across the system
systemctl --user edit hermes-gateway- Add
[Service] Environment="GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/home/ubuntu/gws-credentials-manual.json"systemctl --user daemon-reloadsystemctl --user restart hermes-gatewayvi ~/.bashrcexport GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=$HOME/gws-credentials-manual.jsonsource ~/.bashrchermes gateway
- Test the functionality
- Run this command: echo $GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE
Send an email to name@gmail.com with subject "final test" and body "it works"
Configure Hermes to send email using GWS
- vi ~/.hermes/config.yaml, under agent: section add below section
system_prompt_suffix: |EMAIL SENDING PROTOCOL: When the user asks to send an email to any email address (format: user@domain.com), use the terminal tool to execute this exact command: GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/home/ubuntu/gws-credentials-manual.json gws gmail +send --to ADDRESS --subject "SUBJECT" --body "BODY" Replace ADDRESS with the recipient email, SUBJECT with the subject text, and BODY with the message body. Always wrap SUBJECT and BODY in double quotes. Never use send_message for arbitrary email addresses - only use it for messaging platform users.systemctl --user restart hermes-gateway- Test using Slack whether the setup works:
Send an email to name@gmail.com with subject "system prompt test" and body "testing permanent config"
What this does is, whenever Slack / Whatsapp send a message “Send an email …”, it looks up the system_prompt we added earlier and triggers GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE via terminal. This works reliably well every single time.
Configure Hermes ⇔ Google Sheet integration
- Visit https://console.cloud.google.com/apis/library?project=name
- Search for Google Sheet API and enable it.
- Verify gws has access to Google Sheets
gws sheets --help - Test using
gws sheets spreadsheets get --params '{"spreadsheetId": "YOUR_SPREADSHEET_ID"}' - Add the service to Hermes Gateway
systemctl --user edit hermes-gatewayEnvironment="HERMES_SYSTEM_PROMPT_SUFFIX=EMAIL SENDING PROTOCOL: When the user asks to send an email to any email address, use the terminal tool to execute: GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/home/ubuntu/gws-credentials-manual.json gws gmail +send --to ADDRESS --subject \"SUBJECT\" --body \"BODY\". SHEETS PROTOCOL: For Google Sheets operations, use gws sheets commands with the same GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE environment variable."systemctl --user daemon-reloadsystemctl --user restart hermes-gateway
- Test using Slack / Whatsapp
- Create a new skill called test-add. When I send “test-add” followed by number1, number2 entries like “1111, 2222”, use the terminal tool to run for each entry: GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/home/ubuntu/.hermes/google_token.json gws sheets +append –spreadsheet 12345678900987654321sdfghjkl0987654 –values ‘number1,number2’. If successful respond “Test Add: Updated 👍” followed by entries. If failed respond “Test Add: Failed ❌. Try again” followed by entries.
- Hermes uses skill_manage to create a SKILL.md and a python function associated with it.
- For an even more efficient system, create a python script and tell Slack/Whatsapp to invoke that python script every time it sees a trigger keyword. For example:
- On Whatsapp, send this:
Remember: When I send "Expenses" followed by expense entries like "description, 3750", always use execute_code to run the process_expenses.py script at /home/ubuntu/.hermes/skills/productivity/office-expenses/scripts/process_expenses.py with the entries as argument. Never use write_file. The script handles appending to Google Sheets and returns 👍 or ❌ per entry. - Next time when you invoke using keywords from Slack or Whatsapp, it triggers this terminal command in the background. It works reliably every time.
Please do leave your comments below to help me & rest of the community learn how you improved this setup process or how you plan to use the hermes setup. Would love to learn.
The image was generated using Gemini AI, while the background research and light text editing was done using Claude AI. This writing is to help crystalize my thoughts, more than preaching to the choir.