[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CB2FCT5RKK75GA614W3PWJ":3,"skill-same:01M6CB2FCT5RKK75GA614W3PWJ":149},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":68,"commitSha":69,"skillDirectory":70,"forksCount":71,"repositoryHtmlUrl":72,"repositoryHomepageUrl":6,"ownerHtmlUrl":73,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":74,"install":75,"resources":88},"01M6CB2FCT5RKK75GA614W3PWJ","google-workspace",null,"Gmail, Calendar, Drive, Docs, Sheets via gws CLI or Python.","adnichols\u002Fai-configs","adnichols","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F493746?v=4","01M6C33VRY9WF6XWYPT1AFA7JJ","Aaron Nichols","01M6C33VWTNKGRM92E9G643V4W",5,"MIT","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"google","workspace","google workspace","calendar","gmail","json","credentials","OAuth","email","cloud","https","console","windows","research","google cloud","linux","himalaya","github","python","cli","2026-11-10 10:12:30",false,"---\nname: google-workspace\ndescription: \"Gmail, Calendar, Drive, Docs, Sheets via gws CLI or Python.\"\nversion: 1.2.0\nauthor: Nous Research\nlicense: MIT\nplatforms: [linux, macos, windows]\nrequired_credential_files:\n  - path: google_token.json\n    description: Google OAuth2 token (created by setup script)\n  - path: google_client_secret.json\n    description: Google OAuth2 client credentials (downloaded from Google Cloud Console)\nmetadata:\n  hermes:\n    tags: [Google, Gmail, Calendar, Drive, Sheets, Docs, Contacts, Email, OAuth]\n    homepage: https:\u002F\u002Fgithub.com\u002FNousResearch\u002Fhermes-agent\n    related_skills: [himalaya]\n---\n\n# Google Workspace\n\nGmail, Calendar, Drive, Contacts, Sheets, and Docs — through Hermes-managed OAuth and a thin CLI wrapper. When `gws` is installed, the skill uses it as the execution backend for broader Google Workspace coverage; otherwise it falls back to the bundled Python client implementation.\n\n## References\n\n- `references\u002Fgmail-search-syntax.md` — Gmail search operators (is:unread, from:, newer_than:, etc.)\n- `references\u002Fdaily-brief.md` — daily\u002Fmorning brief procedure: schedule + conflicts + meeting prep + urgent mail from Gmail and Calendar. Load it when the user asks for a morning brief, meeting preparation, or \"what's on my calendar and what email needs attention.\"\n\n## Scripts\n\n- `scripts\u002Fsetup.py` — OAuth2 setup (run once to authorize)\n- `scripts\u002Fgoogle_api.py` — compatibility wrapper CLI. It prefers `gws` for operations when available, while preserving Hermes' existing JSON output contract.\n\n## First-Time Setup\n\nThe setup is fully non-interactive — you drive it step by step so it works\non CLI, Telegram, Discord, or any platform.\n\nRun the setup script with Python from the Hermes environment, not an unrelated\nsystem Python. `--install-deps` syncs Hermes' declared Google extra through PM;\nafter syncing, restart Hermes and rerun the OAuth command. If Hermes is not\nimportable, use `hermes setup` first rather than installing packages with pip.\n\nDefine a shorthand first:\n\n```bash\nGSETUP=\"python ${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fsetup.py\"\n```\n\n### Step 0: Check if already set up\n\n```bash\n$GSETUP --check\n```\n\nIf it prints `AUTHENTICATED`, skip to Usage — setup is already done.\n\n### Step 1: Triage — ask the user what they need\n\nBefore starting OAuth setup, ask the user TWO questions:\n\n**Question 1: \"What Google services do you need? Just email, or also\nCalendar\u002FDrive\u002FSheets\u002FDocs?\"**\n\n- **Email only** → They don't need this skill at all. Use the `himalaya` skill\n  instead — it works with a Gmail App Password (Settings → Security → App\n  Passwords) and takes 2 minutes to set up. No Google Cloud project needed.\n  Load the himalaya skill and follow its setup instructions.\n\n- **Email + Calendar** → Continue with this skill, but use\n  `--services email,calendar` during auth so the consent screen only asks for\n  the scopes they actually need.\n\n- **Calendar\u002FDrive\u002FSheets\u002FDocs only** → Continue with this skill and use a\n  narrower `--services` set like `calendar,drive,sheets,docs`.\n\n- **Full Workspace access** → Continue with this skill and use the default\n  `all` service set.\n\n**Question 2: \"Does your Google account use Advanced Protection (hardware\nsecurity keys required to sign in)? If you're not sure, you probably don't\n— it's something you would have explicitly enrolled in.\"**\n\n- **No \u002F Not sure** → Normal setup. Continue below.\n- **Yes** → Their Workspace admin must add the OAuth client ID to the org's\n  allowed apps list before Step 4 will work. Let them know upfront.\n\n### Step 2: Create OAuth credentials (one-time, ~5 minutes)\n\nTell the user:\n\n> You need a Google Cloud OAuth client. This is a one-time setup:\n>\n> 1. Create or select a project:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fprojectselector2\u002Fhome\u002Fdashboard\n> 2. Enable the required APIs from the API Library:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Flibrary\n>    Enable: Gmail API, Google Calendar API, Google Drive API,\n>    Google Sheets API, Google Docs API, People API\n> 3. Create the OAuth client here:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Fcredentials\n>    Credentials → Create Credentials → OAuth 2.0 Client ID\n> 4. Application type: \"Desktop app\" → Create\n> 5. If the app is still in Testing, add the user's Google account as a test user here:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fauth\u002Faudience\n>    Audience → Test users → Add users\n> 6. Download the JSON file and tell me the file path\n>\n> Important Hermes CLI note: if the file path starts with `\u002F`, do NOT send only the bare path as its own message in the CLI, because it can be mistaken for a slash command. Send it in a sentence instead, like:\n> `The JSON file path is: ~\u002FDownloads\u002Fclient_secret_....json`\n\nOnce they provide the path:\n\n```bash\n$GSETUP --client-secret \u002Fpath\u002Fto\u002Fclient_secret.json\n```\n\nIf they paste the raw client ID \u002F client secret values instead of a file path,\nwrite a valid Desktop OAuth JSON file for them yourself, save it somewhere\nexplicit (for example `~\u002FDownloads\u002Fhermes-google-client-secret.json`), then run\n`--client-secret` against that file.\n\n### Step 3: Get authorization URL\n\nUse the service set chosen in Step 1. Examples:\n\n```bash\n$GSETUP --auth-url --services email,calendar --format json\n$GSETUP --auth-url --services calendar,drive,sheets,docs --format json\n$GSETUP --auth-url --services all --format json\n```\n\nThis returns JSON with an `auth_url` field and also saves the exact URL to\n`~\u002F.hermes\u002Fgoogle_oauth_last_url.txt`.\n\nAgent rules for this step:\n- Extract the `auth_url` field and send that exact URL to the user as a single line.\n- Tell the user that the browser will likely fail on `http:\u002F\u002Flocalhost:1` after approval, and that this is expected.\n- Tell them to copy the ENTIRE redirected URL from the browser address bar.\n- If the user gets `Error 403: access_denied`, send them directly to `https:\u002F\u002Fconsole.cloud.google.com\u002Fauth\u002Faudience` to add themselves as a test user.\n\n### Step 4: Exchange the code\n\nThe user will paste back either a URL like `http:\u002F\u002Flocalhost:1\u002F?code=4\u002F0A...&scope=...`\nor just the code string. Either works. The `--auth-url` step stores a temporary\npending OAuth session locally so `--auth-code` can complete the PKCE exchange\nlater, even on headless systems:\n\n```bash\n$GSETUP --auth-code \"THE_URL_OR_CODE_THE_USER_PASTED\" --format json\n```\n\nIf `--auth-code` fails because the code expired, was already used, or came from\nan older browser tab, it now returns a fresh `fresh_auth_url`. In that case,\nimmediately send the new URL to the user and have them retry with the newest\nbrowser redirect only.\n\n### Step 5: Verify\n\n```bash\n$GSETUP --check\n```\n\nShould print `AUTHENTICATED`. Setup is complete — token refreshes automatically from now on.\n\n### Notes\n\n- Token is stored at `~\u002F.hermes\u002Fgoogle_token.json` and auto-refreshes.\n- Pending OAuth session state\u002Fverifier are stored temporarily at `~\u002F.hermes\u002Fgoogle_oauth_pending.json` until exchange completes.\n- If `gws` is installed, `google_api.py` points it at the same `~\u002F.hermes\u002Fgoogle_token.json` credentials file. Users do not need to run a separate `gws auth login` flow.\n- To revoke: `$GSETUP --revoke`\n\n## Usage\n\nAll commands go through the API script. Set `GAPI` as a shorthand:\n\n```bash\nGAPI=\"python ${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fgoogle_api.py\"\n```\n\n### Gmail\n\n```bash\n# Search (returns JSON array with id, from, subject, date, snippet)\n$GAPI gmail search \"is:unread\" --max 10\n$GAPI gmail search \"from:boss@company.com newer_than:1d\"\n$GAPI gmail search \"has:attachment filename:pdf newer_than:7d\"\n\n# Read full message (returns JSON with body text)\n$GAPI gmail get MESSAGE_ID\n\n# Send\n$GAPI gmail send --to user@example.com --subject \"Hello\" --body \"Message text\"\n$GAPI gmail send --to user@example.com --subject \"Report\" --body \"\u003Ch1>Q4\u003C\u002Fh1>\u003Cp>Details...\u003C\u002Fp>\" --html\n$GAPI gmail send --to user@example.com --subject \"Hello\" --from '\"Research Agent\" \u003Cuser@example.com>' --body \"Message text\"\n\n# Reply (automatically threads and sets In-Reply-To)\n$GAPI gmail reply MESSAGE_ID --body \"Thanks, that works for me.\"\n$GAPI gmail reply MESSAGE_ID --from '\"Support Bot\" \u003Cuser@example.com>' --body \"Thanks\"\n\n# Labels\n$GAPI gmail labels\n$GAPI gmail modify MESSAGE_ID --add-labels LABEL_ID\n$GAPI gmail modify MESSAGE_ID --remove-labels UNREAD\n```\n\n### Calendar\n\n```bash\n# List events (defaults to next 7 days)\n$GAPI calendar list\n$GAPI calendar list --start 2026-03-01T00:00:00Z --end 2026-03-07T23:59:59Z\n\n# Create event (ISO 8601 with timezone required)\n$GAPI calendar create --summary \"Team Standup\" --start 2026-03-01T10:00:00-06:00 --end 2026-03-01T10:30:00-06:00\n$GAPI calendar create --summary \"Lunch\" --start 2026-03-01T12:00:00Z --end 2026-03-01T13:00:00Z --location \"Cafe\"\n$GAPI calendar create --summary \"Review\" --start 2026-03-01T14:00:00Z --end 2026-03-01T15:00:00Z --attendees \"alice@co.com,bob@co.com\"\n\n# Delete event\n$GAPI calendar delete EVENT_ID\n```\n\n### Drive\n\n```bash\n# Search existing files\n$GAPI drive search \"quarterly report\" --max 10\n$GAPI drive search \"mimeType='application\u002Fpdf'\" --raw-query --max 5\n\n# Get metadata for a single file\n$GAPI drive get FILE_ID\n\n# Upload a local file (auto-detects MIME type)\n$GAPI drive upload \u002Fpath\u002Fto\u002Freport.pdf\n$GAPI drive upload \u002Fpath\u002Fto\u002Fimage.png --name \"Logo.png\" --parent FOLDER_ID\n\n# Download (binary files download as-is; Google-native files export to a\n# sensible default — Docs→pdf, Sheets→csv, Slides→pdf, Drawings→png)\n$GAPI drive download FILE_ID\n$GAPI drive download DOC_ID --output ~\u002Fdoc.pdf\n$GAPI drive download DOC_ID --export-mime text\u002Fplain --output ~\u002Fdoc.txt\n\n# Create a folder\n$GAPI drive create-folder \"Reports\"\n$GAPI drive create-folder \"Q4\" --parent FOLDER_ID\n\n# Share\n$GAPI drive share FILE_ID --email alice@example.com --role reader\n$GAPI drive share FILE_ID --email alice@example.com --role writer --notify\n$GAPI drive share FILE_ID --type anyone --role reader        # anyone with link\n$GAPI drive share FILE_ID --type domain --domain example.com --role reader\n\n# Delete — defaults to trash (reversible). Use --permanent to skip the trash.\n$GAPI drive delete FILE_ID\n$GAPI drive delete FILE_ID --permanent\n```\n\n### Contacts\n\n```bash\n$GAPI contacts list --max 20\n```\n\n### Sheets\n\n```bash\n# Create a new spreadsheet\n$GAPI sheets create --title \"Q4 Budget\"\n$GAPI sheets create --title \"Inventory\" --sheet-name \"Stock\"\n\n# Read\n$GAPI sheets get SHEET_ID \"Sheet1!A1:D10\"\n\n# Write\n$GAPI sheets update SHEET_ID \"Sheet1!A1:B2\" --values '[[\"Name\",\"Score\"],[\"Alice\",\"95\"]]'\n\n# Append rows\n$GAPI sheets append SHEET_ID \"Sheet1!A:C\" --values '[[\"new\",\"row\",\"data\"]]'\n```\n\n### Docs\n\n```bash\n# Read (a tabbed Doc returns a \"tabs\" array; single-tab and legacy Docs also return \"body\")\n$GAPI docs get DOC_ID\n$GAPI docs get DOC_ID --tab TAB_ID     # read one tab of a tabbed Doc\n\n# Create a new Doc (optionally seeded with body text)\n$GAPI docs create --title \"Meeting Notes\"\n$GAPI docs create --title \"Draft\" --body \"First paragraph...\"\n\n# Append text to the end of an existing Doc\n$GAPI docs append DOC_ID --text \"Additional content to append\"\n$GAPI docs append DOC_ID --tab TAB_ID --text \"...\"   # --tab required when the Doc has multiple tabs\n```\n\n## Output Format\n\nAll commands return JSON. Parse with `jq` or read directly. Key fields:\n\n- **Gmail search**: `[{id, threadId, from, to, subject, date, snippet, labels}]`\n- **Gmail get**: `{id, threadId, from, to, subject, date, labels, body}`\n- **Gmail send\u002Freply**: `{status: \"sent\", id, threadId}`\n- **Calendar list**: `[{id, summary, start, end, location, description, htmlLink}]`\n- **Calendar create**: `{status: \"created\", id, summary, htmlLink}`\n- **Drive search**: `[{id, name, mimeType, modifiedTime, webViewLink}]`\n- **Drive get**: `{id, name, mimeType, modifiedTime, size, webViewLink, parents, owners}`\n- **Drive upload**: `{status: \"uploaded\", id, name, mimeType, webViewLink}`\n- **Drive download**: `{status: \"downloaded\", id, name, path, mimeType}`\n- **Drive create-folder**: `{status: \"created\", id, name, webViewLink}`\n- **Drive share**: `{status: \"shared\", permissionId, fileId, role, type}`\n- **Drive delete**: `{status: \"trashed\" | \"deleted\", fileId, permanent}`\n- **Contacts list**: `[{name, emails: [...], phones: [...]}]`\n- **Sheets get**: `[[cell, cell, ...], ...]`\n- **Sheets create**: `{status: \"created\", spreadsheetId, title, spreadsheetUrl}`\n- **Docs create**: `{status: \"created\", documentId, title, url}`\n- **Docs append**: `{status: \"appended\", documentId, inserted_at, characters}`\n\n## Rules\n\n1. **Never send email, create\u002Fdelete calendar events, delete Drive files, share files, or modify Docs\u002FSheets without confirming with the user first.** Show what will be done (recipients, file IDs, content, share role) and ask for approval. For `drive delete`, prefer the default trash (reversible) over `--permanent`.\n2. **Check auth before first use** — run `setup.py --check`. If it fails, guide the user through setup.\n3. **Use the Gmail search syntax reference** for complex queries — load it with `skill_view(\"google-workspace\", file_path=\"references\u002Fgmail-search-syntax.md\")`.\n4. **Calendar times must include timezone** — always use ISO 8601 with offset (e.g., `2026-03-01T10:00:00-06:00`) or UTC (`Z`).\n5. **Respect rate limits** — avoid rapid-fire sequential API calls. Batch reads when possible.\n\n## Troubleshooting\n\n| Problem | Fix |\n|---------|-----|\n| `NOT_AUTHENTICATED` | Run setup Steps 2-5 above |\n| `REFRESH_FAILED` | Token revoked or expired — redo Steps 3-5 |\n| `HttpError 403: Insufficient Permission` | Missing API scope — `$GSETUP --revoke` then redo Steps 3-5 |\n| `AUTHENTICATED (partial)` or \"Token missing scopes\" | New write capabilities (Drive write\u002Fdelete, Docs create\u002Fedit) require re-authorization. `$GSETUP --revoke` then redo Steps 3-5 to grant the upgraded scopes. |\n| `HttpError 403: Access Not Configured` | API not enabled — user needs to enable it in Google Cloud Console |\n| `ModuleNotFoundError` | Run `$GSETUP --install-deps` |\n| Advanced Protection blocks auth | Workspace admin must allowlist the OAuth client ID |\n\n## Revoking Access\n\n```bash\n$GSETUP --revoke\n```\n","# Google Workspace\n\nGmail, Calendar, Drive, Contacts, Sheets, and Docs — through Hermes-managed OAuth and a thin CLI wrapper. When `gws` is installed, the skill uses it as the execution backend for broader Google Workspace coverage; otherwise it falls back to the bundled Python client implementation.\n\n## References\n\n- `references\u002Fgmail-search-syntax.md` — Gmail search operators (is:unread, from:, newer_than:, etc.)\n- `references\u002Fdaily-brief.md` — daily\u002Fmorning brief procedure: schedule + conflicts + meeting prep + urgent mail from Gmail and Calendar. Load it when the user asks for a morning brief, meeting preparation, or \"what's on my calendar and what email needs attention.\"\n\n## Scripts\n\n- `scripts\u002Fsetup.py` — OAuth2 setup (run once to authorize)\n- `scripts\u002Fgoogle_api.py` — compatibility wrapper CLI. It prefers `gws` for operations when available, while preserving Hermes' existing JSON output contract.\n\n## First-Time Setup\n\nThe setup is fully non-interactive — you drive it step by step so it works\non CLI, Telegram, Discord, or any platform.\n\nRun the setup script with Python from the Hermes environment, not an unrelated\nsystem Python. `--install-deps` syncs Hermes' declared Google extra through PM;\nafter syncing, restart Hermes and rerun the OAuth command. If Hermes is not\nimportable, use `hermes setup` first rather than installing packages with pip.\n\nDefine a shorthand first:\n\n```bash\nGSETUP=\"python ${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fsetup.py\"\n```\n\n### Step 0: Check if already set up\n\n```bash\n$GSETUP --check\n```\n\nIf it prints `AUTHENTICATED`, skip to Usage — setup is already done.\n\n### Step 1: Triage — ask the user what they need\n\nBefore starting OAuth setup, ask the user TWO questions:\n\n**Question 1: \"What Google services do you need? Just email, or also\nCalendar\u002FDrive\u002FSheets\u002FDocs?\"**\n\n- **Email only** → They don't need this skill at all. Use the `himalaya` skill\n  instead — it works with a Gmail App Password (Settings → Security → App\n  Passwords) and takes 2 minutes to set up. No Google Cloud project needed.\n  Load the himalaya skill and follow its setup instructions.\n\n- **Email + Calendar** → Continue with this skill, but use\n  `--services email,calendar` during auth so the consent screen only asks for\n  the scopes they actually need.\n\n- **Calendar\u002FDrive\u002FSheets\u002FDocs only** → Continue with this skill and use a\n  narrower `--services` set like `calendar,drive,sheets,docs`.\n\n- **Full Workspace access** → Continue with this skill and use the default\n  `all` service set.\n\n**Question 2: \"Does your Google account use Advanced Protection (hardware\nsecurity keys required to sign in)? If you're not sure, you probably don't\n— it's something you would have explicitly enrolled in.\"**\n\n- **No \u002F Not sure** → Normal setup. Continue below.\n- **Yes** → Their Workspace admin must add the OAuth client ID to the org's\n  allowed apps list before Step 4 will work. Let them know upfront.\n\n### Step 2: Create OAuth credentials (one-time, ~5 minutes)\n\nTell the user:\n\n> You need a Google Cloud OAuth client. This is a one-time setup:\n>\n> 1. Create or select a project:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fprojectselector2\u002Fhome\u002Fdashboard\n> 2. Enable the required APIs from the API Library:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Flibrary\n>    Enable: Gmail API, Google Calendar API, Google Drive API,\n>    Google Sheets API, Google Docs API, People API\n> 3. Create the OAuth client here:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Fcredentials\n>    Credentials → Create Credentials → OAuth 2.0 Client ID\n> 4. Application type: \"Desktop app\" → Create\n> 5. If the app is still in Testing, add the user's Google account as a test user here:\n>    https:\u002F\u002Fconsole.cloud.google.com\u002Fauth\u002Faudience\n>    Audience → Test users → Add users\n> 6. Download the JSON file and tell me the file path\n>\n> Important Hermes CLI note: if the file path starts with `\u002F`, do NOT send only the bare path as its own message in the CLI, because it can be mistaken for a slash command. Send it in a sentence instead, like:\n> `The JSON file path is: ~\u002FDownloads\u002Fclient_secret_....json`\n\nOnce they provide the path:\n\n```bash\n$GSETUP --client-secret \u002Fpath\u002Fto\u002Fclient_secret.json\n```\n\nIf they paste the raw client ID \u002F client secret values instead of a file path,\nwrite a valid Desktop OAuth JSON file for them yourself, save it somewhere\nexplicit (for example `~\u002FDownloads\u002Fhermes-google-client-secret.json`), then run\n`--client-secret` against that file.\n\n### Step 3: Get authorization URL\n\nUse the service set chosen in Step 1. Examples:\n\n```bash\n$GSETUP --auth-url --services email,calendar --format json\n$GSETUP --auth-url --services calendar,drive,sheets,docs --format json\n$GSETUP --auth-url --services all --format json\n```\n\nThis returns JSON with an `auth_url` field and also saves the exact URL to\n`~\u002F.hermes\u002Fgoogle_oauth_last_url.txt`.\n\nAgent rules for this step:\n- Extract the `auth_url` field and send that exact URL to the user as a single line.\n- Tell the user that the browser will likely fail on `http:\u002F\u002Flocalhost:1` after approval, and that this is expected.\n- Tell them to copy the ENTIRE redirected URL from the browser address bar.\n- If the user gets `Error 403: access_denied`, send them directly to `https:\u002F\u002Fconsole.cloud.google.com\u002Fauth\u002Faudience` to add themselves as a test user.\n\n### Step 4: Exchange the code\n\nThe user will paste back either a URL like `http:\u002F\u002Flocalhost:1\u002F?code=4\u002F0A...&scope=...`\nor just the code string. Either works. The `--auth-url` step stores a temporary\npending OAuth session locally so `--auth-code` can complete the PKCE exchange\nlater, even on headless systems:\n\n```bash\n$GSETUP --auth-code \"THE_URL_OR_CODE_THE_USER_PASTED\" --format json\n```\n\nIf `--auth-code` fails because the code expired, was already used, or came from\nan older browser tab, it now returns a fresh `fresh_auth_url`. In that case,\nimmediately send the new URL to the user and have them retry with the newest\nbrowser redirect only.\n\n### Step 5: Verify\n\n```bash\n$GSETUP --check\n```\n\nShould print `AUTHENTICATED`. Setup is complete — token refreshes automatically from now on.\n\n### Notes\n\n- Token is stored at `~\u002F.hermes\u002Fgoogle_token.json` and auto-refreshes.\n- Pending OAuth session state\u002Fverifier are stored temporarily at `~\u002F.hermes\u002Fgoogle_oauth_pending.json` until exchange completes.\n- If `gws` is installed, `google_api.py` points it at the same `~\u002F.hermes\u002Fgoogle_token.json` credentials file. Users do not need to run a separate `gws auth login` flow.\n- To revoke: `$GSETUP --revoke`\n\n## Usage\n\nAll commands go through the API script. Set `GAPI` as a shorthand:\n\n```bash\nGAPI=\"python ${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fgoogle_api.py\"\n```\n\n### Gmail\n\n```bash\n# Search (returns JSON array with id, from, subject, date, snippet)\n$GAPI gmail search \"is:unread\" --max 10\n$GAPI gmail search \"from:boss@company.com newer_than:1d\"\n$GAPI gmail search \"has:attachment filename:pdf newer_than:7d\"\n\n# Read full message (returns JSON with body text)\n$GAPI gmail get MESSAGE_ID\n\n# Send\n$GAPI gmail send --to user@example.com --subject \"Hello\" --body \"Message text\"\n$GAPI gmail send --to user@example.com --subject \"Report\" --body \"\u003Ch1>Q4\u003C\u002Fh1>\u003Cp>Details...\u003C\u002Fp>\" --html\n$GAPI gmail send --to user@example.com --subject \"Hello\" --from '\"Research Agent\" \u003Cuser@example.com>' --body \"Message text\"\n\n# Reply (automatically threads and sets In-Reply-To)\n$GAPI gmail reply MESSAGE_ID --body \"Thanks, that works for me.\"\n$GAPI gmail reply MESSAGE_ID --from '\"Support Bot\" \u003Cuser@example.com>' --body \"Thanks\"\n\n# Labels\n$GAPI gmail labels\n$GAPI gmail modify MESSAGE_ID --add-labels LABEL_ID\n$GAPI gmail modify MESSAGE_ID --remove-labels UNREAD\n```\n\n### Calendar\n\n```bash\n# List events (defaults to next 7 days)\n$GAPI calendar list\n$GAPI calendar list --start 2026-03-01T00:00:00Z --end 2026-03-07T23:59:59Z\n\n# Create event (ISO 8601 with timezone required)\n$GAPI calendar create --summary \"Team Standup\" --start 2026-03-01T10:00:00-06:00 --end 2026-03-01T10:30:00-06:00\n$GAPI calendar create --summary \"Lunch\" --start 2026-03-01T12:00:00Z --end 2026-03-01T13:00:00Z --location \"Cafe\"\n$GAPI calendar create --summary \"Review\" --start 2026-03-01T14:00:00Z --end 2026-03-01T15:00:00Z --attendees \"alice@co.com,bob@co.com\"\n\n# Delete event\n$GAPI calendar delete EVENT_ID\n```\n\n### Drive\n\n```bash\n# Search existing files\n$GAPI drive search \"quarterly report\" --max 10\n$GAPI drive search \"mimeType='application\u002Fpdf'\" --raw-query --max 5\n\n# Get metadata for a single file\n$GAPI drive get FILE_ID\n\n# Upload a local file (auto-detects MIME type)\n$GAPI drive upload \u002Fpath\u002Fto\u002Freport.pdf\n$GAPI drive upload \u002Fpath\u002Fto\u002Fimage.png --name \"Logo.png\" --parent FOLDER_ID\n\n# Download (binary files download as-is; Google-native files export to a\n# sensible default — Docs→pdf, Sheets→csv, Slides→pdf, Drawings→png)\n$GAPI drive download FILE_ID\n$GAPI drive download DOC_ID --output ~\u002Fdoc.pdf\n$GAPI drive download DOC_ID --export-mime text\u002Fplain --output ~\u002Fdoc.txt\n\n# Create a folder\n$GAPI drive create-folder \"Reports\"\n$GAPI drive create-folder \"Q4\" --parent FOLDER_ID\n\n# Share\n$GAPI drive share FILE_ID --email alice@example.com --role reader\n$GAPI drive share FILE_ID --email alice@example.com --role writer --notify\n$GAPI drive share FILE_ID --type anyone --role reader        # anyone with link\n$GAPI drive share FILE_ID --type domain --domain example.com --role reader\n\n# Delete — defaults to trash (reversible). Use --permanent to skip the trash.\n$GAPI drive delete FILE_ID\n$GAPI drive delete FILE_ID --permanent\n```\n\n### Contacts\n\n```bash\n$GAPI contacts list --max 20\n```\n\n### Sheets\n\n```bash\n# Create a new spreadsheet\n$GAPI sheets create --title \"Q4 Budget\"\n$GAPI sheets create --title \"Inventory\" --sheet-name \"Stock\"\n\n# Read\n$GAPI sheets get SHEET_ID \"Sheet1!A1:D10\"\n\n# Write\n$GAPI sheets update SHEET_ID \"Sheet1!A1:B2\" --values '[[\"Name\",\"Score\"],[\"Alice\",\"95\"]]'\n\n# Append rows\n$GAPI sheets append SHEET_ID \"Sheet1!A:C\" --values '[[\"new\",\"row\",\"data\"]]'\n```\n\n### Docs\n\n```bash\n# Read (a tabbed Doc returns a \"tabs\" array; single-tab and legacy Docs also return \"body\")\n$GAPI docs get DOC_ID\n$GAPI docs get DOC_ID --tab TAB_ID     # read one tab of a tabbed Doc\n\n# Create a new Doc (optionally seeded with body text)\n$GAPI docs create --title \"Meeting Notes\"\n$GAPI docs create --title \"Draft\" --body \"First paragraph...\"\n\n# Append text to the end of an existing Doc\n$GAPI docs append DOC_ID --text \"Additional content to append\"\n$GAPI docs append DOC_ID --tab TAB_ID --text \"...\"   # --tab required when the Doc has multiple tabs\n```\n\n## Output Format\n\nAll commands return JSON. Parse with `jq` or read directly. Key fields:\n\n- **Gmail search**: `[{id, threadId, from, to, subject, date, snippet, labels}]`\n- **Gmail get**: `{id, threadId, from, to, subject, date, labels, body}`\n- **Gmail send\u002Freply**: `{status: \"sent\", id, threadId}`\n- **Calendar list**: `[{id, summary, start, end, location, description, htmlLink}]`\n- **Calendar create**: `{status: \"created\", id, summary, htmlLink}`\n- **Drive search**: `[{id, name, mimeType, modifiedTime, webViewLink}]`\n- **Drive get**: `{id, name, mimeType, modifiedTime, size, webViewLink, parents, owners}`\n- **Drive upload**: `{status: \"uploaded\", id, name, mimeType, webViewLink}`\n- **Drive download**: `{status: \"downloaded\", id, name, path, mimeType}`\n- **Drive create-folder**: `{status: \"created\", id, name, webViewLink}`\n- **Drive share**: `{status: \"shared\", permissionId, fileId, role, type}`\n- **Drive delete**: `{status: \"trashed\" | \"deleted\", fileId, permanent}`\n- **Contacts list**: `[{name, emails: [...], phones: [...]}]`\n- **Sheets get**: `[[cell, cell, ...], ...]`\n- **Sheets create**: `{status: \"created\", spreadsheetId, title, spreadsheetUrl}`\n- **Docs create**: `{status: \"created\", documentId, title, url}`\n- **Docs append**: `{status: \"appended\", documentId, inserted_at, characters}`\n\n## Rules\n\n1. **Never send email, create\u002Fdelete calendar events, delete Drive files, share files, or modify Docs\u002FSheets without confirming with the user first.** Show what will be done (recipients, file IDs, content, share role) and ask for approval. For `drive delete`, prefer the default trash (reversible) over `--permanent`.\n2. **Check auth before first use** — run `setup.py --check`. If it fails, guide the user through setup.\n3. **Use the Gmail search syntax reference** for complex queries — load it with `skill_view(\"google-workspace\", file_path=\"references\u002Fgmail-search-syntax.md\")`.\n4. **Calendar times must include timezone** — always use ISO 8601 with offset (e.g., `2026-03-01T10:00:00-06:00`) or UTC (`Z`).\n5. **Respect rate limits** — avoid rapid-fire sequential API calls. Batch reads when possible.\n\n## Troubleshooting\n\n| Problem | Fix |\n|---------|-----|\n| `NOT_AUTHENTICATED` | Run setup Steps 2-5 above |\n| `REFRESH_FAILED` | Token revoked or expired — redo Steps 3-5 |\n| `HttpError 403: Insufficient Permission` | Missing API scope — `$GSETUP --revoke` then redo Steps 3-5 |\n| `AUTHENTICATED (partial)` or \"Token missing scopes\" | New write capabilities (Drive write\u002Fdelete, Docs create\u002Fedit) require re-authorization. `$GSETUP --revoke` then redo Steps 3-5 to grant the upgraded scopes. |\n| `HttpError 403: Access Not Configured` | API not enabled — user needs to enable it in Google Cloud Console |\n| `ModuleNotFoundError` | Run `$GSETUP --install-deps` |\n| Advanced Protection blocks auth | Workspace admin must allowlist the OAuth client ID |\n\n## Revoking Access\n\n```bash\n$GSETUP --revoke\n```\n",{"name":5,"author":44,"license":15,"version":45,"metadata":46,"platforms":59,"description":7,"required_credential_files":61},"Nous Research","1.2.0",{"hermes":47},{"tags":48,"homepage":57,"related_skills":58},[49,50,51,52,53,54,55,56,26],"Google","Gmail","Calendar","Drive","Sheets","Docs","Contacts","Email","https:\u002F\u002Fgithub.com\u002FNousResearch\u002Fhermes-agent",[35],[34,60,31],"macos",[62,65],{"path":63,"description":64},"google_token.json","Google OAuth2 token (created by setup script)",{"path":66,"description":67},"google_client_secret.json","Google OAuth2 client credentials (downloaded from Google Cloud Console)","main","64e2fc9afa7bb3da1138eb73399144d0e7e73e9d","_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace",4,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs","https:\u002F\u002Fgithub.com\u002Fadnichols","2026-11-06 00:28:38",{"source":8,"skillName":5,"commands":76,"prompt":86,"zipAvailable":87},[77,80,83],{"tool":78,"command":79},"npx","npx skills add adnichols\u002Fai-configs --skill google-workspace",{"tool":81,"command":82},"bunx","bunx skills add adnichols\u002Fai-configs --skill google-workspace",{"tool":84,"command":85},"pnpm","pnpm dlx skills add adnichols\u002Fai-configs --skill google-workspace","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002FSKILL.md",true,[89,95,99,103,107,111,115,119,123,127,131,137,141,145],{"path":90,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":93,"sourceHtmlUrl":94},"references\u002Fcore_concepts.md","REFERENCE","参考文档",14394,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fcore_concepts.md",{"path":96,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":97,"sourceHtmlUrl":98},"references\u002Fdaily-brief.md",3217,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Freferences\u002Fdaily-brief.md",{"path":100,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":101,"sourceHtmlUrl":102},"references\u002Fdatasets.md",10951,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fdatasets.md",{"path":104,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":105,"sourceHtmlUrl":106},"references\u002Fgmail-search-syntax.md",2150,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Freferences\u002Fgmail-search-syntax.md",{"path":108,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":109,"sourceHtmlUrl":110},"references\u002Fknowledge_graphs.md",8480,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fknowledge_graphs.md",{"path":112,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":113,"sourceHtmlUrl":114},"references\u002Fmodels_architectures.md",13694,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fmodels_architectures.md",{"path":116,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":117,"sourceHtmlUrl":118},"references\u002Fmolecular_generation.md",10074,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fmolecular_generation.md",{"path":120,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":121,"sourceHtmlUrl":122},"references\u002Fmolecular_property_prediction.md",5667,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fmolecular_property_prediction.md",{"path":124,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":125,"sourceHtmlUrl":126},"references\u002Fprotein_modeling.md",7737,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fprotein_modeling.md",{"path":128,"resourceType":91,"resourceTypeDesc":92,"sizeBytes":129,"sourceHtmlUrl":130},"references\u002Fretrosynthesis.md",11537,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Ftorchdrug\u002Freferences\u002Fretrosynthesis.md",{"path":132,"resourceType":133,"resourceTypeDesc":134,"sizeBytes":135,"sourceHtmlUrl":136},"scripts\u002F_hermes_home.py","SCRIPT","脚本",1636,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002F_hermes_home.py",{"path":138,"resourceType":133,"resourceTypeDesc":134,"sizeBytes":139,"sourceHtmlUrl":140},"scripts\u002Fgoogle_api.py",47061,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fgoogle_api.py",{"path":142,"resourceType":133,"resourceTypeDesc":134,"sizeBytes":143,"sourceHtmlUrl":144},"scripts\u002Fgws_bridge.py",4368,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fgws_bridge.py",{"path":146,"resourceType":133,"resourceTypeDesc":134,"sizeBytes":147,"sourceHtmlUrl":148},"scripts\u002Fsetup.py",17414,"https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fproductivity\u002Fgoogle-workspace\u002Fscripts\u002Fsetup.py",[150,168,202,227,238,254],{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":39},"01M6CB7RN791P5RRRCJWWC7DAR","blocked-page-recovery","Use when a fetch fails: 403\u002F429, paywall, WAF, bot wall.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fweb\u002Fblocked-page-recovery\u002FSKILL.md",[],[157,158,159,160,161,162,163,164,165,166,167,31,32,34,60],"recovery","page","blocked page recovery","bot","fallback","use","fetch","hermes agent","hermes","Citations","waf",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":187,"publishedAt":39},"01M6CB7NQY2VVYCQJ1QBXACQF4","writing-plans","Use when creating or updating executable software plans. Keep plans as local files unless the user explicitly asks to register them in Doct.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fsoftware-development\u002Fwriting-plans\u002FSKILL.md",[174,179,182],{"categoryNo":175,"categoryName":176,"taxonomyType":177,"taxonomyTypeDesc":178},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",{"categoryNo":180,"categoryName":181,"taxonomyType":177,"taxonomyTypeDesc":178},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":183,"categoryName":184,"taxonomyType":185,"taxonomyTypeDesc":186},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[188,189,190,191,192,193,194,195,196,197,198,199,162,200,164,165,201],"writing","writing plans","documentation","test","workflow","design","user","development","planning","files","implementation","html","ops","plan",{"skillNo":203,"name":204,"nameZh":6,"description":205,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":206,"categories":207,"keywords":217,"publishedAt":39},"01M6CB7JME246KZQHP73Z2STDF","test-driven-development","TDD: enforce RED-GREEN-REFACTOR, tests before code.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fsoftware-development\u002Ftest-driven-development\u002FSKILL.md",[208,211,214],{"categoryNo":209,"categoryName":210,"taxonomyType":177,"taxonomyTypeDesc":178},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":212,"categoryName":213,"taxonomyType":177,"taxonomyTypeDesc":178},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":215,"categoryName":216,"taxonomyType":185,"taxonomyTypeDesc":186},"01JBSEEDCAT000000000000037","律师与法务",[191,195,218,219,220,164,165,221,201,222,223,224,60,225,34,226,31],"test driven development","red-green-refactor","superpowers","quality","refactor","code","debugging","tdd","testing",{"skillNo":228,"name":229,"nameZh":6,"description":230,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":231,"categories":232,"keywords":234,"publishedAt":39},"01M6CB7FQ407KQTD4Z9VAWKY54","systematic-debugging","4-phase root cause debugging: understand bugs before fixing.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fsoftware-development\u002Fsystematic-debugging\u002FSKILL.md",[233],{"categoryNo":212,"categoryName":213,"taxonomyType":177,"taxonomyTypeDesc":178},[224,235,195,220,164,165,236,201,237,31,191,34,60],"systematic debugging","troubleshooting","investigation",{"skillNo":239,"name":240,"nameZh":6,"description":241,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":242,"categories":243,"keywords":247,"publishedAt":39},"01M6CB7D57MK88HE5YPZHKH68Q","spike","Throwaway experiments to validate an idea before build.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fsoftware-development\u002Fspike\u002FSKILL.md",[244],{"categoryNo":245,"categoryName":246,"taxonomyType":177,"taxonomyTypeDesc":178},"01JBSEEDCAT000000000000021","资料检索与研究",[240,31,248,249,32,250,34,60,251,252,253,164,165,201,196],"validate","experiments","prototype","feasibility","sketch","experiment",{"skillNo":255,"name":256,"nameZh":6,"description":257,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":258,"categories":259,"keywords":264,"publishedAt":39},"01M6CB7APAQ37YE5YE1MAAFT42","simplify-code","Parallel 3-agent cleanup of recent code changes.","https:\u002F\u002Fgithub.com\u002Fadnichols\u002Fai-configs\u002Fblob\u002Fmain\u002F_hermes\u002Fdefault\u002Fskills\u002Fsoftware-development\u002Fsimplify-code\u002FSKILL.md",[260,261],{"categoryNo":180,"categoryName":181,"taxonomyType":177,"taxonomyTypeDesc":178},{"categoryNo":262,"categoryName":263,"taxonomyType":185,"taxonomyTypeDesc":186},"01JBSEEDCAT000000000000030","开发工程师",[265,266,223,267,164,165,268,201,222,269,270,271,195,31,191,34,272,60],"simplify code","simplify","subagent","parallel","code-review","delegation","cleanup","review"]