NousResearch/hermes-agent

google-workspace required_credential_files and OAuth file access in remote terminals

Cluster 16452 · skills. Data as of

Nothing open on GitHub. Fix merged in #19886 on 4 May 2026. Check it covers your case.

The short answer

0open issues
0open PRs
3items grouped
Known?
Yes. 3 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #19886. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
Nothing open on GitHub.

Three members relate to the google-workspace skill: two pull request titles about restoring required_credential_files in SKILL.md, and one bug report about being unable to read an OAuth file in remote terminals. The titles suggest a shared theme around credential file handling, but the link between the bug and the fix is inferred from titles alone.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #19886 fix(google-workspace): restore required_credential_files in SKILL.md

    merged to main

    files: skills/productivity/google-workspace/SKILL.md, tests/skills/test_google_workspace_credential_files.py

    Show the diff
    • skills/productivity/google-workspace/SKILL.md
      @@ -1,9 +1,14 @@
       ---
       name: google-workspace
       description: "Gmail, Calendar, Drive, Docs, Sheets via gws CLI or Python."
      -version: 1.0.0
      +version: 1.0.1
       author: Nous Research
       license: MIT
      +required_credential_files:
      +  - path: google_token.json
      +    description: Google OAuth2 token (created by setup script)
      +  - path: google_client_secret.json
      +    description: Google OAuth2 client credentials (downloaded from Google Cloud Console)
       metadata:
         hermes:
           tags: [Google, Gmail, Calendar, Drive, Sheets, Docs, Contacts, Email, OAuth]
    • tests/skills/test_google_workspace_credential_files.py
      @@ -0,0 +1,102 @@
      +"""Regression test: google-workspace SKILL.md must declare required_credential_files.
      +
      +PR #9931 accidentally removed the required_credential_files header, which broke
      +credential file mounting in Docker/Modal remote backends (#16452). This test
      +prevents the regression from silently reappearing.
      +"""
      +
      +from __future__ import annotations
      +
      +import os
      +from pathlib import Path
      +from unittest.mock import patch
      +
      +import pytest
      +
      +SKILL_MD = (
      +    Path(__file__).resolve().parents[2]
      +    / "skills/productivity/google-workspace/SKILL.md"
      +)
      +
      +_EXPECTED_PATHS = {"google_token.json", "google_client_secret.json"}
      +
      +
      +def _parse_frontmatter(content: str) -> dict:
      +    from agent.skill_utils import parse_frontmatter
      +
      +    fm, _ = parse_frontmatter(content)
      +    return fm
      +
      +
      +class TestGoogleWorkspaceCredentialFiles:
      +    def test_required_credential_files_present_in_skill_md(self):
      +        content = SKILL_MD.read_text(encoding="utf-8")
      +        fm = _parse_frontmatter(content)
      +        entries = fm.get("required_credential_files")
      +        assert entries, "required_credential_files missing from google-workspace SKILL.md"
      +        assert isinstance(entries, list), "required_credential_files must be a list"
      +        paths = {
      +            (e["path"] if isinstance(e, dict) else e)
      +            for e in entries
      +        }
      +        assert _EXPECTED_PATHS <= paths, (
      +            f"Missing entries in required_credential_files: [redacted:secret-assignment] - paths}"
      +        )
      +
      +    def test_entries_are_registered_when_files_exist(self, tmp_path):
      +        hermes_home = tmp_path / ".hermes"
      +        hermes_home.mkdir()
      +        (hermes_home / "google_token.json").write_text("{}")
      +        (hermes_home / "google_client_secret.json").write_text("{}")
      +
      +        from tools.credential_files import (
      +            clear_credential_files,
      +            get_credential_file_mounts,
      +            register_credential_files,
      +        )
      +
      +        clear_credential_files()
      +        try:
      +            content = SKILL_MD.read_text(encoding="utf-8")
      +            fm = _parse_frontmatter(content)
      +            entries = fm.get("required_credential_files", [])
      +
      +            with patch.dict(os.environ, {"HERMES_HOME": str(hermes_home)}):
      +                missing = register_credential_files(entries)
      +
      +            assert missing == [], f"Unexpected missing files: {missing}"
      +            mounts = get_credential_file_mounts()
      +            container_paths = {m["container_path"] for m in mounts}
      +            assert "/root/.hermes/google_token.json" in container_paths
      +            assert "/root/.hermes/google_client_secret.json" in container_paths
      +        finally:
      +            clear_credential_files()
      +
      +    def test_missing_token_is_reported(self, tmp_path):
      +        """google_token.json absent (first-time setup) — reported as missing, client secret still mounts."""
      +        hermes_home = tmp_path / ".hermes"
      +        hermes_home.mkdir()
      +        (hermes_home / "google_client_secret.json").write_text("{}")
      +
      +        from tools.credential_files import (
      +            clear_credential_files,
      +            get_credential_file_mounts,
      +            register_credential_files,
      +        )
      +
      +        clear_credential_files()
      +        try:
      +            content = SKILL_MD.read_text(encoding="utf-8")
      +            fm = _parse_frontmatter(content)
      +            entries = fm.get("required_credential_files", [])
      +
      +            with patch.dict(os.environ, {"HERMES_HOME": str(hermes_home)}):
      +                missing = register_credential_files(entries)
      +
      +            assert "google_token.json" in missing
      +            mounts = get_credential_file_mounts()
      +            container_paths = {m["container_path"] for m in mounts}
      +            assert "/root/.hermes/google_client_secret.json" in container_paths
      +            assert "/root/.hermes/google_token.json" not in container_paths
      +        finally:
      +            clear_credential_files()

1 PR closed without merging

From the close comments: merged via another change 1

  • #16470 fix(google-workspace): restore required_credential_files in SKILL.md (#16452) · merged via another change → #19886
Closed issues · 1
  • Closed#16452[Bug]: google-workspace can't read oauth file in remote terminals
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
skills
Merged PRs
#19886
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
4 May 2026

For your agent

The same facts, typed.