Skip to content

feat(gws): add Google Workspace CLI plugin#31

Merged
cblecker merged 2 commits intomainfrom
feat/gws-plugin
Mar 18, 2026
Merged

feat(gws): add Google Workspace CLI plugin#31
cblecker merged 2 commits intomainfrom
feat/gws-plugin

Conversation

@cblecker
Copy link
Owner

@cblecker cblecker commented Mar 17, 2026

Summary

  • Add gws plugin vendoring 61 curated upstream gws generate-skills skills (7 services, 12 helpers, 6 workflows, 2 personas, 33 recipes) scoped to current OAuth grants (Gmail, Calendar, Drive, Docs, Sheets, Slides, Meet)
  • Add SessionStart hook to verify gws CLI availability
  • Add /gws-sync curation skill (.claude/skills/gws-sync.md) for ongoing upstream synchronization
  • Exempt vendored gws/skills/** from markdownlint (upstream formatting)

Test plan

  • claude plugin validate ./gws passes
  • claude plugin validate . passes
  • markdownlint-cli2 "**/*.md" — 0 errors
  • CI lint and validate workflows pass
  • Start a new session and verify gws SessionStart hook fires
  • Invoke a gws skill (e.g. gws:gws-gmail-triage) and verify it loads

Summary by CodeRabbit

  • New Features

    • New Google Workspace CLI plugin providing 30+ skills for Gmail, Calendar, Drive, Sheets, Docs, Slides, Meet, workflows and helper commands.
    • Pre-built personas (Executive Assistant, Team Lead) and many recipe workflows for common productivity tasks.
    • Session-start hook that informs users about the gws CLI availability and installation steps.
  • Documentation

    • Comprehensive skill guides, usage examples, and plugin listing added across docs and README.

Vendor curated gws generate-skills output as a managed plugin with
SessionStart hook, 61 skills (7 services, 12 helpers, 6 workflows,
2 personas, 33 recipes), and a /gws-sync curation skill for ongoing
upstream synchronization. Skills are scoped to current OAuth grants
(Gmail, Calendar, Drive, Docs, Sheets, Slides, Meet).

Assisted-by: Claude:claude-opus-4-6
@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

Warning

Ignoring CodeRabbit configuration file changes. For security, only the configuration from the base branch is applied for open source repositories.

Walkthrough

Adds a new Google Workspace CLI plugin named "gws": plugin registration and metadata, a SessionStart hook, linting exclusions, repository docs updates, and a large set of new skill documentation files (core services, sub-skills, workflows, personas, and ~30 recipe SKILLs) plus a sync HOWTO.

Changes

Cohort / File(s) Summary
Plugin registration & config
/.claude-plugin/marketplace.json, gws/.claude-plugin/plugin.json, gws/hooks/hooks.json, .markdownlint-cli2.jsonc, .coderabbit.yaml
Registers gws in marketplace, adds plugin metadata, adds SessionStart hook to surface gws CLI install/help, excludes gws/skills/** from markdown linting, and updates review path filters.
Top-level docs
CLAUDE.md, README.md, gws/README.md, .claude/skills/gws-sync.md
Adds gws entry to repo docs, README plugin list, plugin README, and a detailed gws-sync guide for syncing upstream skills.
Core service skill docs
gws/skills/gws-shared/SKILL.md, gws/skills/gws-calendar/SKILL.md, gws/skills/gws-docs/SKILL.md, gws/skills/gws-drive/SKILL.md, gws/skills/gws-gmail/SKILL.md, gws/skills/gws-meet/SKILL.md, gws/skills/gws-sheets/SKILL.md, gws/skills/gws-slides/SKILL.md
New comprehensive SKILL.md files defining core Google Workspace service commands, resources, discovery guidance, and prerequisites (auth/global flags).
Focused operation sub-skills
gws/skills/gws-calendar-*, gws/skills/gws-docs-write/SKILL.md, gws/skills/gws-drive-upload/SKILL.md, gws/skills/gws-gmail-*, gws/skills/gws-sheets-*
Adds targeted SKILL.md docs for specific operations (agenda, insert, docs write, drive upload, gmail send/reply/forward/triage/watch, sheets read/append) with flags, examples, and cautions for write actions.
Workflow & recipe skills
gws/skills/gws-workflow/..., gws/skills/recipe-*/SKILL.md (many files)
Adds workflow SKILLs and ~30 recipe SKILL.md files documenting multi-step automations combining services (email→task, meeting prep, backups, bulk operations, scheduling, sharing, etc.).
Persona skills
gws/skills/persona-exec-assistant/SKILL.md, gws/skills/persona-team-lead/SKILL.md
Adds persona-guides that tie workflows and skills together for specific roles.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a Google Workspace CLI plugin to the repository.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Stable And Deterministic Test Names ✅ Passed The PR adds a Google Workspace CLI plugin with skill documentation and configuration files. No Ginkgo test files or test names are present in the changes.
Test Structure And Quality ✅ Passed This PR contains only documentation and configuration files with no Go test files or Ginkgo test code, making the custom check not applicable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/gws-plugin
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🧹 Nitpick comments (12)
gws/skills/recipe-bulk-download-folder/SKILL.md (2)

22-22: Simplify the shell quoting for better usability.

The nested quoting pattern '{"q": "'\''FOLDER_ID'\'' in parents"}' is technically correct but unnecessarily complex and error-prone for users. Consider using double-quoted strings with escaped inner quotes for clarity.

📝 Proposed clearer quoting approach
-1. List files in folder: `gws drive files list --params '{"q": "'\''FOLDER_ID'\'' in parents"}' --format json`
+1. List files in folder: `gws drive files list --params "{\"q\": \"'FOLDER_ID' in parents\"}" --format json`

This produces the same result but is much easier to read and maintain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-bulk-download-folder/SKILL.md` at line 22, Replace the
nested single-quote escaping in the example command for listing files with a
simpler double-quoted outer string and escaped inner quotes; update the example
line containing the gws CLI invocation (the `gws drive files list --params`
example) to use "--params \"{\\\"q\\\": \\\"FOLDER_ID in parents\\\"}\"" style
quoting so it is easier to read and less error-prone while preserving the same
JSON parameter structure.

22-24: Clarify the workflow iteration logic.

The steps present individual commands but don't explain how to connect them. Step 1 outputs a JSON list, while steps 2-3 operate on individual file IDs. Consider adding guidance on how to parse the JSON output and iterate through files, or provide a complete shell script example that ties all steps together.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-bulk-download-folder/SKILL.md` around lines 22 - 24, The
steps show separate commands (gws drive files list, gws drive files get, gws
drive files export) but lack guidance on connecting the JSON output from gws
drive files list to per-file downloads/exports; update SKILL.md to explain how
to parse the JSON output (e.g., extract each fileId and mimeType) and iterate
over results, and add a concise shell workflow example that uses a JSON parser
(such as jq) to loop through the list, decide between get vs export based on
mimeType, and call gws drive files get or gws drive files export for each fileId
so readers can run the full folder download flow end-to-end.
gws/skills/recipe-forward-labeled-emails/SKILL.md (2)

23-23: Clarify how to extract MSG_ID from step 1 output.

Step 2 references MSG_ID as a placeholder without explaining how to extract the message ID from the step 1 list command output.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-forward-labeled-emails/SKILL.md` at line 23, Clarify that
MSG_ID comes from the "id" field in the JSON output of the first step (the `gws
gmail users messages list` command) and instruct the reader to extract it (for
example by selecting the "id" property from the listed messages) before using it
in `gws gmail users messages get`; reference the `gws gmail users messages list`
and `gws gmail users messages get` commands so maintainers can update SKILL.md
to show where MSG_ID originates and how to pull the "id" value from the list
output.

24-26: Clarify multi-line body formatting in the example.

The email body spans multiple lines (24-26) in a way that may be ambiguous. Clarify whether the line breaks are literal (part of the email body) or if this is a documentation formatting artifact.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-forward-labeled-emails/SKILL.md` around lines 24 - 26,
Clarify whether the example command in SKILL.md (the `gws gmail +send --to
manager@company.com --subject 'FW: [Original Subject]' --body 'Forwarding for
your review:\n\n[Original Message Body]'` example) contains literal line breaks
in the email body or if the blank line is just documentation formatting; update
the example to explicitly show the intended behavior by either replacing the
multi-line body with an escaped newline representation (e.g., \n) or by showing
a clear here-doc/multi-line syntax variant and add a short note stating "line
breaks are literal" or "line breaks are only for doc formatting" so readers know
whether the blank line will appear in the sent email.
gws/skills/gws-workflow-email-to-task/SKILL.md (1)

42-42: Consider using a CAUTION block for write operations.

Line 42 mentions user confirmation in the Tips section, but the pattern in gws-gmail-send uses a formatted CAUTION block for write operations. Using consistent formatting across skills would improve clarity:

> [!CAUTION]
> This is a **write** command — confirm with the user before executing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-workflow-email-to-task/SKILL.md` at line 42, Replace the
informal confirmation sentence in SKILL.md (the Tips section line that reads
"Creates a new task — confirm with the user before executing.") with a formatted
CAUTION block consistent with gws-gmail-send; specifically add a block that uses
the markdown admonition syntax ([!CAUTION]) and a bold "write" warning such as
"This is a **write** command — confirm with the user before executing." to make
the intent and risk explicit.
gws/skills/recipe-share-doc-and-notify/SKILL.md (1)

22-24: Clarify how to extract and use DOC_ID between steps.

Steps 2 and 3 reference DOC_ID as a placeholder, but the recipe doesn't explain how to extract the file ID from the step 1 output and interpolate it into subsequent commands. Users may be unclear on the manual substitution required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-share-doc-and-notify/SKILL.md` around lines 22 - 24, The
recipe omits how to obtain and reuse the file ID from the output of gws drive
files list; after running gws drive files list capture the fileId (e.g., from
the returned JSON at items[0].id or by parsing the output for "id") and
substitute that value for DOC_ID in the subsequent commands. Specifically,
document that users should extract the id from the gws drive files list output
and then use that id when calling gws drive permissions create (fileId: DOC_ID)
and when composing the link passed to gws gmail +send
(https://docs.google.com/document/d/DOC_ID), or show a one-line example of
assigning the parsed id to a variable and using it in those two commands.
gws/skills/gws-workflow-file-announce/SKILL.md (1)

43-43: Consider using a CAUTION block for write operations.

Line 43 notes this is a write command in the Tips section, but other skills (e.g., gws-gmail-send) use a formatted CAUTION block for write operations. Consider using the same pattern for consistency:

> [!CAUTION]
> This is a **write** command — confirm with the user before executing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-workflow-file-announce/SKILL.md` at line 43, Replace the plain
"This is a write command — sends a Chat message." line in SKILL.md (the Tips
section) with a formatted CAUTION block used by other skills (e.g.,
gws-gmail-send): insert a block that begins with the CAUTION admonition and
states that this is a write command and that the user should confirm before
executing, e.g., a CAUTION block that says this is a **write** command — confirm
with the user before executing.
gws/skills/recipe-draft-email-from-doc/SKILL.md (1)

22-24: Manual copy step reduces recipe automation.

Step 2 requires manual text extraction ("Copy the text from the body content"), which breaks the automation pattern seen in other recipes. Consider documenting a more automated approach using JSON parsing (e.g., jq) to extract the body content programmatically.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-draft-email-from-doc/SKILL.md` around lines 22 - 24,
Replace the manual "Copy the text from the body content" step with an automated
JSON extraction using the output of the `gws docs documents get` command and
then pass that extracted body to the `gws gmail +send` command; specifically,
parse the JSON response to pull the document body (e.g., the JSON path for the
body content) using a JSON tool (jq or similar), store or stream that extracted
string, and use command substitution or a pipe to provide it as the `--body`
argument to `gws gmail +send` so the recipe is end-to-end automated rather than
requiring manual copy/paste.
gws/skills/recipe-copy-sheet-for-new-month/SKILL.md (1)

24-24: Use the copied sheet ID dynamically instead of a fixed value.

On Line 24, sheetId: 123 and "February 2025" are fixed literals. This makes the recipe brittle: the rename call should use the sheetId returned from Step 2 and a caller-provided month label.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-copy-sheet-for-new-month/SKILL.md` at line 24, Replace the
hard-coded sheetId: 123 and fixed title "February 2025" in the gws sheets
spreadsheets batchUpdate command with the sheetId returned by the
duplicate-sheet call in Step 2 and a caller-provided month label; specifically,
change the example invocation of "gws sheets spreadsheets batchUpdate" so it
reads the new tab id from the Step 2 response (the duplicate/duplicateSheet
reply) instead of 123 and injects a variable like a provided monthLabel instead
of "February 2025".
gws/skills/gws-calendar-agenda/SKILL.md (1)

55-55: Minor wording polish in See Also.

Line 55 reads awkwardly (“All manage calendars and events commands”). Consider “All calendar and event management commands.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-calendar-agenda/SKILL.md` at line 55, Replace the awkward
phrasing in the See Also entry for gws-calendar: change the text "-
[gws-calendar](../gws-calendar/SKILL.md) — All manage calendars and events
commands" to read something clearer like "All calendar and event management
commands" so the line becomes "- [gws-calendar](../gws-calendar/SKILL.md) — All
calendar and event management commands".
gws/skills/gws-calendar-insert/SKILL.md (1)

31-32: Optional: Minor time format terminology inconsistency.

The flags table (lines 31-32) mentions "ISO 8601" format, while the Tips section (line 46) specifies "RFC3339 format." Since RFC3339 is a profile of ISO 8601 and the examples correctly show RFC3339 format, this doesn't affect functionality—but future upstream updates could unify the terminology for clarity.

Also applies to: 46-46

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-calendar-insert/SKILL.md` around lines 31 - 32, Update the
time format wording for the `--start` and `--end` flags to match the Tips
section by replacing "ISO 8601" with "RFC3339 (a profile of ISO 8601)" so the
flags table and the Tips section use consistent terminology; ensure both the
table entries for `--start` and `--end` and any example text mention RFC3339
explicitly to avoid future confusion.
.claude/skills/gws-sync.md (1)

50-52: Define fallback when metadata.openclaw.requires.skills is missing.

The process currently assumes that key exists; add an explicit fallback ([]) so sync classification doesn’t fail on skills without dependency metadata.

Suggested wording tweak
-1. Read its `SKILL.md` frontmatter to get the `metadata.openclaw.requires.skills` list
+1. Read its `SKILL.md` frontmatter to get `metadata.openclaw.requires.skills` (default to `[]` if missing)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/skills/gws-sync.md around lines 50 - 52, When reading a skill's
SKILL.md frontmatter to get metadata.openclaw.requires.skills during the sync
classification step, treat the field as optional and default to an empty array
([]) when the key is missing or undefined; update the reader logic (the SKILL.md
frontmatter parsing/assignment used in the "Read its `SKILL.md` frontmatter to
get the `metadata.openclaw.requires.skills` list" step) to use
metadata.openclaw.requires.skills || [] so that skills without dependency
metadata do not break the classification.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/skills/gws-sync.md:
- Around line 16-17: The script uses $TMPDIR directly which can be empty and
cause unsafe paths; introduce a safe variable (e.g.,
GWS_TMP_DIR="${TMPDIR:-/tmp}/gws-skills-upstream") and update the invocations of
gws generate-skills --output-dir and the cleanup rm -rf to use GWS_TMP_DIR
instead of $TMPDIR/gws-skills-upstream, and apply the same replacement for the
other occurrence(s) in the file; ensure the new variable is defined before any
generate/cleanup commands.

In `@gws/skills/gws-docs-write/SKILL.md`:
- Line 49: Update the "See Also" link text in SKILL.md by capitalizing the
product name: change the link description string "[gws-docs] — All read and
write google docs commands" so that "google docs" becomes "Google Docs" (i.e.,
"[gws-docs] — All read and write Google Docs commands") to correctly capitalize
the product name.

In `@gws/skills/gws-drive-upload/SKILL.md`:
- Line 52: Update the "See Also" description in SKILL.md by replacing the
current fragment "[gws-drive](../gws-drive/SKILL.md) — All manage files,
folders, and shared drives commands" with a grammatically correct phrase such as
"All commands to manage files, folders, and shared drives" so the link text
reads: [gws-drive](../gws-drive/SKILL.md) — All commands to manage files,
folders, and shared drives; edit the SKILL.md entry that contains this link to
apply the change.

In `@gws/skills/gws-shared/SKILL.md`:
- Around line 63-70: Replace the inaccurate guidance about zsh `!` expansion in
SKILL.md: change the example block that labels single-quoted ranges as "WRONG"
to indicate single quotes are SAFE for the range literal, e.g. update the
comment above gws sheets +read --spreadsheet ... --range 'Sheet1!A1:D10' from
"WRONG (zsh will mangle the !)" to something like "SAFE (single quotes)" and
keep the double-quoted example labeled "ALSO SAFE"; ensure the examples show
both 'Sheet1!A1:D10' and "Sheet1!A1:D10" as safe options so the command gws
sheets +read --spreadsheet ID --range 'Sheet1!A1:D10' is correctly documented.

In `@gws/skills/persona-exec-assistant/SKILL.md`:
- Around line 10-15: The README references an unsupported skill name "gws-chat"
in both the skills array and the PREREQUISITE line, making the persona
non-runnable; update the skills array and the PREREQUISITE text in SKILL.md to
only list actually shipped skills (e.g., replace "gws-chat" with a supported
skill such as "gws-meet" or remove it entirely) and ensure the names in the
skills: ["gws-gmail", "gws-calendar", "gws-drive", "gws-chat"] line and the
PREREQUISITE sentence match the plugin's real capabilities.

In `@gws/skills/recipe-batch-invite-to-event/SKILL.md`:
- Around line 22-24: Step 2 currently overwrites attendees by sending a fresh
"attendees" array; instead, read the existing attendees from the result of Step
1 (the output of the first gws calendar events get), merge those attendee
objects with the new emails (avoid duplicates by email, and preserve attendee
object fields like displayName/responseStatus), then call gws calendar events
patch with the merged attendees array (sendUpdates as before) so existing
attendees are preserved and new ones appended.

In `@gws/skills/recipe-block-focus-time/SKILL.md`:
- Line 22: The example command hardcodes a past date ("2025-01-20") in the JSON
body for the calendar event (look for the gws command with calendarId "primary"
and the event summary "Focus Time"); update the JSON start.dateTime and
end.dateTime fields to use a placeholder (e.g., "YYYY-MM-DDTHH:MM:SS") or a
relative/future date token (e.g., "next Monday" or a script-generated ISO
timestamp) instead of a fixed past date so the example creates a future
recurring focus block rather than a historical entry.

In `@gws/skills/recipe-create-events-from-sheet/SKILL.md`:
- Around line 22-23: The example uses a hard-coded past timestamp in the
calendar insert command; replace the fixed ISO datetimes with row-derived
placeholders so the recipe is evergreen: update the second step's `gws calendar
+insert` invocation to use placeholders like `--start START_ISO` and `--end
END_ISO` (or `--start '{{START_ISO}}'`/`--end '{{END_ISO}}'` depending on
template syntax) and ensure the first step (`gws sheets +read --range
"Events!A2:D"`) maps sheet columns to START_ISO/END_ISO/ATTENDEES/SUMMARY so the
`gws calendar +insert` command references those placeholders instead of
`2026-01-20T09:00:00`.

In `@gws/skills/recipe-create-gmail-filter/SKILL.md`:
- Around line 23-24: Step 2 creates a label but the recipe never shows
extracting the actual label ID required by the filter; update the doc to add a
sub-step that captures the "id" field from the output of the gws gmail users
labels create command (gws gmail users labels create) and then substitute that
id into the addLabelIds array when calling gws gmail users settings filters
create (use the "id" value, not the label name, in addLabelIds).

In `@gws/skills/recipe-create-presentation/SKILL.md`:
- Around line 9-16: The prerequisites block in SKILL.md is missing the gws-drive
skill required by Step 3's `gws drive permissions create` command; update the
requires section (the YAML under "requires:" where bins: ["gws"] and skills:
["gws-slides"] are listed) to include "gws-drive" (e.g., add "gws-drive" to the
skills array) so the recipe loads both gws-slides and gws-drive before running
the sharing step.

In `@gws/skills/recipe-create-shared-drive/SKILL.md`:
- Line 22: Replace the fixed requestId value in the example `gws drive drives
create` command with a truly unique placeholder or an inline UUID generation
hint so readers won't reuse the same id; update the `requestId` in SKILL.md (the
example command that currently contains "unique-id-123") to show either a clear
placeholder like <UUID> or indicate generating a UUID at runtime (e.g., using a
uuid generator) so the example demonstrates creating a unique requestId for
idempotency.

In `@gws/skills/recipe-plan-weekly-schedule/SKILL.md`:
- Around line 22-25: The example in SKILL.md uses inconsistent years across
commands (the freebusy example uses 2025 while the insert example uses 2026);
update the dates so all steps use the same year (e.g., change the freebusy JSON
timeMin/timeMax to 2026-01-20 and 2026-01-25 or change the insert/start/end to
2025-01-21) so the sequence in the gws calendar +agenda, gws calendar freebusy
query, and gws calendar +insert examples are consistent; modify the lines
containing the freebusy JSON and the +insert timestamp in SKILL.md to match the
chosen year.

In `@gws/skills/recipe-post-mortem-setup/SKILL.md`:
- Line 22: The recipe incorrectly calls the helper gws docs +write with
--title/--body flags; instead, first create the document using the documents
create command (gws docs documents create --params ...) to obtain the document
ID, then call the existing +write helper (which accepts --document <ID> and
--text <TEXT>) to append the body text; update the SKILL.md step to create the
post-mortem, capture the returned document ID, and pass that ID into gws docs
+write --document <ID> --text '<body>' so the workflow matches the helper
signatures.

In `@gws/skills/recipe-schedule-recurring-event/SKILL.md`:
- Line 22: The example recurring event command hardcodes a past start date/time
("2024-03-18T09:00:00") which can confuse users; update the SKILL.md example
(the gws calendar events insert command and its JSON payload) to use either a
placeholder (e.g., "<ISO_DATETIME_FUTURE>") or a clearly future-relative example
(e.g., start date computed relative to now) and note the expectation for an ISO
8601 datetime and timezone in the "start"/"end" fields so readers can substitute
a current future date when testing.

In `@gws/skills/recipe-share-event-materials/SKILL.md`:
- Around line 22-24: Step 2 is ambiguous: clarify that the gws drive permissions
create command must be executed for each attendee returned by gws calendar
events get; instruct the author to add a short note explaining how to extract
attendee emails from the event JSON (from the attendees array returned by gws
calendar events get with EVENT_ID) and that the gws drive permissions create
call (using FILE_ID) should be repeated for each attendee.email (or provide a
simple shell/scripting example outline) so readers understand how to iterate
over all attendees.

---

Nitpick comments:
In @.claude/skills/gws-sync.md:
- Around line 50-52: When reading a skill's SKILL.md frontmatter to get
metadata.openclaw.requires.skills during the sync classification step, treat the
field as optional and default to an empty array ([]) when the key is missing or
undefined; update the reader logic (the SKILL.md frontmatter parsing/assignment
used in the "Read its `SKILL.md` frontmatter to get the
`metadata.openclaw.requires.skills` list" step) to use
metadata.openclaw.requires.skills || [] so that skills without dependency
metadata do not break the classification.

In `@gws/skills/gws-calendar-agenda/SKILL.md`:
- Line 55: Replace the awkward phrasing in the See Also entry for gws-calendar:
change the text "- [gws-calendar](../gws-calendar/SKILL.md) — All manage
calendars and events commands" to read something clearer like "All calendar and
event management commands" so the line becomes "-
[gws-calendar](../gws-calendar/SKILL.md) — All calendar and event management
commands".

In `@gws/skills/gws-calendar-insert/SKILL.md`:
- Around line 31-32: Update the time format wording for the `--start` and
`--end` flags to match the Tips section by replacing "ISO 8601" with "RFC3339 (a
profile of ISO 8601)" so the flags table and the Tips section use consistent
terminology; ensure both the table entries for `--start` and `--end` and any
example text mention RFC3339 explicitly to avoid future confusion.

In `@gws/skills/gws-workflow-email-to-task/SKILL.md`:
- Line 42: Replace the informal confirmation sentence in SKILL.md (the Tips
section line that reads "Creates a new task — confirm with the user before
executing.") with a formatted CAUTION block consistent with gws-gmail-send;
specifically add a block that uses the markdown admonition syntax ([!CAUTION])
and a bold "write" warning such as "This is a **write** command — confirm with
the user before executing." to make the intent and risk explicit.

In `@gws/skills/gws-workflow-file-announce/SKILL.md`:
- Line 43: Replace the plain "This is a write command — sends a Chat message."
line in SKILL.md (the Tips section) with a formatted CAUTION block used by other
skills (e.g., gws-gmail-send): insert a block that begins with the CAUTION
admonition and states that this is a write command and that the user should
confirm before executing, e.g., a CAUTION block that says this is a **write**
command — confirm with the user before executing.

In `@gws/skills/recipe-bulk-download-folder/SKILL.md`:
- Line 22: Replace the nested single-quote escaping in the example command for
listing files with a simpler double-quoted outer string and escaped inner
quotes; update the example line containing the gws CLI invocation (the `gws
drive files list --params` example) to use "--params \"{\\\"q\\\": \\\"FOLDER_ID
in parents\\\"}\"" style quoting so it is easier to read and less error-prone
while preserving the same JSON parameter structure.
- Around line 22-24: The steps show separate commands (gws drive files list, gws
drive files get, gws drive files export) but lack guidance on connecting the
JSON output from gws drive files list to per-file downloads/exports; update
SKILL.md to explain how to parse the JSON output (e.g., extract each fileId and
mimeType) and iterate over results, and add a concise shell workflow example
that uses a JSON parser (such as jq) to loop through the list, decide between
get vs export based on mimeType, and call gws drive files get or gws drive files
export for each fileId so readers can run the full folder download flow
end-to-end.

In `@gws/skills/recipe-copy-sheet-for-new-month/SKILL.md`:
- Line 24: Replace the hard-coded sheetId: 123 and fixed title "February 2025"
in the gws sheets spreadsheets batchUpdate command with the sheetId returned by
the duplicate-sheet call in Step 2 and a caller-provided month label;
specifically, change the example invocation of "gws sheets spreadsheets
batchUpdate" so it reads the new tab id from the Step 2 response (the
duplicate/duplicateSheet reply) instead of 123 and injects a variable like a
provided monthLabel instead of "February 2025".

In `@gws/skills/recipe-draft-email-from-doc/SKILL.md`:
- Around line 22-24: Replace the manual "Copy the text from the body content"
step with an automated JSON extraction using the output of the `gws docs
documents get` command and then pass that extracted body to the `gws gmail
+send` command; specifically, parse the JSON response to pull the document body
(e.g., the JSON path for the body content) using a JSON tool (jq or similar),
store or stream that extracted string, and use command substitution or a pipe to
provide it as the `--body` argument to `gws gmail +send` so the recipe is
end-to-end automated rather than requiring manual copy/paste.

In `@gws/skills/recipe-forward-labeled-emails/SKILL.md`:
- Line 23: Clarify that MSG_ID comes from the "id" field in the JSON output of
the first step (the `gws gmail users messages list` command) and instruct the
reader to extract it (for example by selecting the "id" property from the listed
messages) before using it in `gws gmail users messages get`; reference the `gws
gmail users messages list` and `gws gmail users messages get` commands so
maintainers can update SKILL.md to show where MSG_ID originates and how to pull
the "id" value from the list output.
- Around line 24-26: Clarify whether the example command in SKILL.md (the `gws
gmail +send --to manager@company.com --subject 'FW: [Original Subject]' --body
'Forwarding for your review:\n\n[Original Message Body]'` example) contains
literal line breaks in the email body or if the blank line is just documentation
formatting; update the example to explicitly show the intended behavior by
either replacing the multi-line body with an escaped newline representation
(e.g., \n) or by showing a clear here-doc/multi-line syntax variant and add a
short note stating "line breaks are literal" or "line breaks are only for doc
formatting" so readers know whether the blank line will appear in the sent
email.

In `@gws/skills/recipe-share-doc-and-notify/SKILL.md`:
- Around line 22-24: The recipe omits how to obtain and reuse the file ID from
the output of gws drive files list; after running gws drive files list capture
the fileId (e.g., from the returned JSON at items[0].id or by parsing the output
for "id") and substitute that value for DOC_ID in the subsequent commands.
Specifically, document that users should extract the id from the gws drive files
list output and then use that id when calling gws drive permissions create
(fileId: DOC_ID) and when composing the link passed to gws gmail +send
(https://docs.google.com/document/d/DOC_ID), or show a one-line example of
assigning the parsed id to a variable and using it in those two commands.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: cblecker/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a72244a7-d63d-4019-b87b-053167f2577f

📥 Commits

Reviewing files that changed from the base of the PR and between 5b26201 and 656d7a8.

📒 Files selected for processing (69)
  • .claude-plugin/marketplace.json
  • .claude/skills/gws-sync.md
  • .markdownlint-cli2.jsonc
  • CLAUDE.md
  • README.md
  • gws/.claude-plugin/plugin.json
  • gws/README.md
  • gws/hooks/hooks.json
  • gws/skills/gws-calendar-agenda/SKILL.md
  • gws/skills/gws-calendar-insert/SKILL.md
  • gws/skills/gws-calendar/SKILL.md
  • gws/skills/gws-docs-write/SKILL.md
  • gws/skills/gws-docs/SKILL.md
  • gws/skills/gws-drive-upload/SKILL.md
  • gws/skills/gws-drive/SKILL.md
  • gws/skills/gws-gmail-forward/SKILL.md
  • gws/skills/gws-gmail-reply-all/SKILL.md
  • gws/skills/gws-gmail-reply/SKILL.md
  • gws/skills/gws-gmail-send/SKILL.md
  • gws/skills/gws-gmail-triage/SKILL.md
  • gws/skills/gws-gmail-watch/SKILL.md
  • gws/skills/gws-gmail/SKILL.md
  • gws/skills/gws-meet/SKILL.md
  • gws/skills/gws-shared/SKILL.md
  • gws/skills/gws-sheets-append/SKILL.md
  • gws/skills/gws-sheets-read/SKILL.md
  • gws/skills/gws-sheets/SKILL.md
  • gws/skills/gws-slides/SKILL.md
  • gws/skills/gws-workflow-email-to-task/SKILL.md
  • gws/skills/gws-workflow-file-announce/SKILL.md
  • gws/skills/gws-workflow-meeting-prep/SKILL.md
  • gws/skills/gws-workflow-standup-report/SKILL.md
  • gws/skills/gws-workflow-weekly-digest/SKILL.md
  • gws/skills/gws-workflow/SKILL.md
  • gws/skills/persona-exec-assistant/SKILL.md
  • gws/skills/persona-team-lead/SKILL.md
  • gws/skills/recipe-backup-sheet-as-csv/SKILL.md
  • gws/skills/recipe-batch-invite-to-event/SKILL.md
  • gws/skills/recipe-block-focus-time/SKILL.md
  • gws/skills/recipe-bulk-download-folder/SKILL.md
  • gws/skills/recipe-compare-sheet-tabs/SKILL.md
  • gws/skills/recipe-copy-sheet-for-new-month/SKILL.md
  • gws/skills/recipe-create-doc-from-template/SKILL.md
  • gws/skills/recipe-create-events-from-sheet/SKILL.md
  • gws/skills/recipe-create-expense-tracker/SKILL.md
  • gws/skills/recipe-create-gmail-filter/SKILL.md
  • gws/skills/recipe-create-meet-space/SKILL.md
  • gws/skills/recipe-create-presentation/SKILL.md
  • gws/skills/recipe-create-shared-drive/SKILL.md
  • gws/skills/recipe-create-vacation-responder/SKILL.md
  • gws/skills/recipe-draft-email-from-doc/SKILL.md
  • gws/skills/recipe-email-drive-link/SKILL.md
  • gws/skills/recipe-find-free-time/SKILL.md
  • gws/skills/recipe-find-large-files/SKILL.md
  • gws/skills/recipe-forward-labeled-emails/SKILL.md
  • gws/skills/recipe-generate-report-from-sheet/SKILL.md
  • gws/skills/recipe-label-and-archive-emails/SKILL.md
  • gws/skills/recipe-log-deal-update/SKILL.md
  • gws/skills/recipe-organize-drive-folder/SKILL.md
  • gws/skills/recipe-plan-weekly-schedule/SKILL.md
  • gws/skills/recipe-post-mortem-setup/SKILL.md
  • gws/skills/recipe-reschedule-meeting/SKILL.md
  • gws/skills/recipe-review-meet-participants/SKILL.md
  • gws/skills/recipe-save-email-attachments/SKILL.md
  • gws/skills/recipe-save-email-to-doc/SKILL.md
  • gws/skills/recipe-schedule-recurring-event/SKILL.md
  • gws/skills/recipe-share-doc-and-notify/SKILL.md
  • gws/skills/recipe-share-event-materials/SKILL.md
  • gws/skills/recipe-share-folder-with-team/SKILL.md

## See Also

- [gws-shared](../gws-shared/SKILL.md) — Global flags and auth
- [gws-docs](../gws-docs/SKILL.md) — All read and write google docs commands
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Capitalize product name in “See Also”.

On Line 49, change “google docs” to “Google Docs”.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~49-~49: Did you mean “Google Docs”?
Context: ...gws-docs/SKILL.md) — All read and write google docs commands

(GOOGLE_PRODUCTS)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-docs-write/SKILL.md` at line 49, Update the "See Also" link
text in SKILL.md by capitalizing the product name: change the link description
string "[gws-docs] — All read and write google docs commands" so that "google
docs" becomes "Google Docs" (i.e., "[gws-docs] — All read and write Google Docs
commands") to correctly capitalize the product name.

## See Also

- [gws-shared](../gws-shared/SKILL.md) — Global flags and auth
- [gws-drive](../gws-drive/SKILL.md) — All manage files, folders, and shared drives commands
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Polish “See Also” description grammar.

On Line 52, consider changing to “All commands to manage files, folders, and shared drives” for readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-drive-upload/SKILL.md` at line 52, Update the "See Also"
description in SKILL.md by replacing the current fragment
"[gws-drive](../gws-drive/SKILL.md) — All manage files, folders, and shared
drives commands" with a grammatically correct phrase such as "All commands to
manage files, folders, and shared drives" so the link text reads:
[gws-drive](../gws-drive/SKILL.md) — All commands to manage files, folders, and
shared drives; edit the SKILL.md entry that contains this link to apply the
change.

Comment on lines +63 to +70
- **zsh `!` expansion:** Sheet ranges like `Sheet1!A1` contain `!` which zsh interprets as history expansion. Use double quotes with escaped inner quotes instead of single quotes:
```bash
# WRONG (zsh will mangle the !)
gws sheets +read --spreadsheet ID --range 'Sheet1!A1:D10'

# CORRECT
gws sheets +read --spreadsheet ID --range "Sheet1!A1:D10"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In zsh, does history expansion for ! occur inside single-quoted strings?

💡 Result:

No. In zsh, history expansion starting with ! can occur “anywhere on the command line, including inside double quotes,” but not inside single quotes ('...') (and also not inside $'...' C-style quotes, or when ! is backslash-escaped). [1]


Update zsh ! history expansion guidance—single quotes are safe.

The current documentation incorrectly marks single-quoted ranges as wrong. In zsh, history expansion for ! does not occur inside single quotes; it only occurs in unquoted strings or double-quoted strings. Single quotes are the safest choice for Sheet1!A1 ranges.

✏️ Suggested doc correction
-- **zsh `!` expansion:** Sheet ranges like `Sheet1!A1` contain `!` which zsh interprets as history expansion. Use double quotes with escaped inner quotes instead of single quotes:
+- **zsh `!` expansion:** Sheet ranges like `Sheet1!A1` contain `!`, which can trigger history expansion in zsh when unquoted or in double quotes. Prefer single quotes (or escape `!` in double quotes):
   ```bash
-  # WRONG (zsh will mangle the !)
-  gws sheets +read --spreadsheet ID --range 'Sheet1!A1:D10'
-
-  # CORRECT
+  # SAFE (single quotes)
+  gws sheets +read --spreadsheet ID --range 'Sheet1!A1:D10'
+
+  # ALSO SAFE
   gws sheets +read --spreadsheet ID --range "Sheet1!A1:D10"
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
- **zsh `!` expansion:** Sheet ranges like `Sheet1!A1` contain `!`, which can trigger history expansion in zsh when unquoted or in double quotes. Prefer single quotes (or escape `!` in double quotes):
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/gws-shared/SKILL.md` around lines 63 - 70, Replace the inaccurate
guidance about zsh `!` expansion in SKILL.md: change the example block that
labels single-quoted ranges as "WRONG" to indicate single quotes are SAFE for
the range literal, e.g. update the comment above gws sheets +read --spreadsheet
... --range 'Sheet1!A1:D10' from "WRONG (zsh will mangle the !)" to something
like "SAFE (single quotes)" and keep the double-quoted example labeled "ALSO
SAFE"; ensure the examples show both 'Sheet1!A1:D10' and "Sheet1!A1:D10" as safe
options so the command gws sheets +read --spreadsheet ID --range 'Sheet1!A1:D10'
is correctly documented.

Comment on lines +10 to +15
skills: ["gws-gmail", "gws-calendar", "gws-drive", "gws-chat"]
---

# Executive Assistant

> **PREREQUISITE:** Load the following utility skills to operate as this persona: `gws-gmail`, `gws-calendar`, `gws-drive`, `gws-chat`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Prerequisite likely references an unsupported skill (gws-chat).

On Line 10 and Line 15, this persona requires gws-chat, but the PR scope lists supported services as Gmail, Calendar, Drive, Docs, Sheets, Slides, and Meet. If gws-chat is not actually shipped in this plugin, this persona becomes non-runnable as documented.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/persona-exec-assistant/SKILL.md` around lines 10 - 15, The README
references an unsupported skill name "gws-chat" in both the skills array and the
PREREQUISITE line, making the persona non-runnable; update the skills array and
the PREREQUISITE text in SKILL.md to only list actually shipped skills (e.g.,
replace "gws-chat" with a supported skill such as "gws-meet" or remove it
entirely) and ensure the names in the skills: ["gws-gmail", "gws-calendar",
"gws-drive", "gws-chat"] line and the PREREQUISITE sentence match the plugin's
real capabilities.


## Steps

1. Create shared drive: `gws drive drives create --params '{"requestId": "unique-id-123"}' --json '{"name": "Project X"}'`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use a truly unique requestId in the example command.

On Line 22, the fixed requestId (unique-id-123) is easy to copy verbatim and reuse, which can cause confusing idempotent behavior on subsequent runs. Prefer showing a UUID placeholder or generation inline.

Suggested documentation tweak
-1. Create shared drive: `gws drive drives create --params '{"requestId": "unique-id-123"}' --json '{"name": "Project X"}'`
+1. Create shared drive: `gws drive drives create --params '{"requestId": "REPLACE_WITH_UUID"}' --json '{"name": "Project X"}'`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. Create shared drive: `gws drive drives create --params '{"requestId": "unique-id-123"}' --json '{"name": "Project X"}'`
1. Create shared drive: `gws drive drives create --params '{"requestId": "REPLACE_WITH_UUID"}' --json '{"name": "Project X"}'`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-create-shared-drive/SKILL.md` at line 22, Replace the fixed
requestId value in the example `gws drive drives create` command with a truly
unique placeholder or an inline UUID generation hint so readers won't reuse the
same id; update the `requestId` in SKILL.md (the example command that currently
contains "unique-id-123") to show either a clear placeholder like <UUID> or
indicate generating a UUID at runtime (e.g., using a uuid generator) so the
example demonstrates creating a unique requestId for idempotency.

Comment on lines +22 to +25
1. Check this week's agenda: `gws calendar +agenda`
2. Check free/busy for the week: `gws calendar freebusy query --json '{"timeMin": "2025-01-20T00:00:00Z", "timeMax": "2025-01-25T00:00:00Z", "items": [{"id": "primary"}]}'`
3. Add a new event: `gws calendar +insert --summary 'Deep Work Block' --start '2026-01-21T14:00:00' --end '2026-01-21T16:00:00'`
4. Review updated schedule: `gws calendar +agenda`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent years in example dates.

Step 2 uses 2025 dates (2025-01-20, 2025-01-25) while step 3 uses 2026 dates (2026-01-21). Consider aligning the years for consistency in this example workflow.

📝 Suggested fix
-2. Check free/busy for the week: `gws calendar freebusy query --json '{"timeMin": "2025-01-20T00:00:00Z", "timeMax": "2025-01-25T00:00:00Z", "items": [{"id": "primary"}]}'`
-3. Add a new event: `gws calendar +insert --summary 'Deep Work Block' --start '2026-01-21T14:00:00' --end '2026-01-21T16:00:00'`
+2. Check free/busy for the week: `gws calendar freebusy query --json '{"timeMin": "2026-01-20T00:00:00Z", "timeMax": "2026-01-25T00:00:00Z", "items": [{"id": "primary"}]}'`
+3. Add a new event: `gws calendar +insert --summary 'Deep Work Block' --start '2026-01-21T14:00:00' --end '2026-01-21T16:00:00'`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-plan-weekly-schedule/SKILL.md` around lines 22 - 25, The
example in SKILL.md uses inconsistent years across commands (the freebusy
example uses 2025 while the insert example uses 2026); update the dates so all
steps use the same year (e.g., change the freebusy JSON timeMin/timeMax to
2026-01-20 and 2026-01-25 or change the insert/start/end to 2025-01-21) so the
sequence in the gws calendar +agenda, gws calendar freebusy query, and gws
calendar +insert examples are consistent; modify the lines containing the
freebusy JSON and the +insert timestamp in SKILL.md to match the chosen year.


## Steps

1. Create post-mortem doc: `gws docs +write --title 'Post-Mortem: [Incident]' --body '## Summary\n\n## Timeline\n\n## Root Cause\n\n## Action Items'`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the flags supported by gws docs +write helper command
rg -A 20 "^## (Usage|Flags)" gws/skills/gws-docs-write/SKILL.md

Repository: cblecker/claude-plugins

Length of output: 617


🏁 Script executed:

#!/bin/bash
# Search for commands that create new documents
rg -l "create.*document|new.*doc" gws/skills/gws-docs*/SKILL.md

Repository: cblecker/claude-plugins

Length of output: 95


🏁 Script executed:

cat -n gws/skills/gws-docs/SKILL.md | head -100

Repository: cblecker/claude-plugins

Length of output: 1953


🏁 Script executed:

cat -n gws/skills/recipe-post-mortem-setup/SKILL.md | sed -n '15,30p'

Repository: cblecker/claude-plugins

Length of output: 797


Critical: Command syntax doesn't match helper definition.

The recipe invokes gws docs +write --title ... --body ..., but the +write helper only accepts --document <ID> and --text <TEXT> flags. The +write helper appends text to an existing document; it doesn't create a new document.

To fix this, use gws docs documents create --params '{"title":"Post-Mortem: [Incident]"}' to create the document first, then capture the document ID and use +write to append the body content if needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-post-mortem-setup/SKILL.md` at line 22, The recipe
incorrectly calls the helper gws docs +write with --title/--body flags; instead,
first create the document using the documents create command (gws docs documents
create --params ...) to obtain the document ID, then call the existing +write
helper (which accepts --document <ID> and --text <TEXT>) to append the body
text; update the SKILL.md step to create the post-mortem, capture the returned
document ID, and pass that ID into gws docs +write --document <ID> --text
'<body>' so the workflow matches the helper signatures.


## Steps

1. Create recurring event: `gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "Weekly Standup", "start": {"dateTime": "2024-03-18T09:00:00", "timeZone": "America/New_York"}, "end": {"dateTime": "2024-03-18T09:30:00", "timeZone": "America/New_York"}, "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"], "attendees": [{"email": "team@company.com"}]}'`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Recurring event example uses a stale past start date.

Line 22 hardcodes 2024-03-18..., which is now historical and can confuse users validating this recipe in 2026+. Prefer placeholders or a clearly future-relative example.

Proposed doc fix
-1. Create recurring event: `gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "Weekly Standup", "start": {"dateTime": "2024-03-18T09:00:00", "timeZone": "America/New_York"}, "end": {"dateTime": "2024-03-18T09:30:00", "timeZone": "America/New_York"}, "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"], "attendees": [{"email": "team@company.com"}]}'`
+1. Create recurring event: `gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "Weekly Standup", "start": {"dateTime": "START_ISO_LOCAL", "timeZone": "America/New_York"}, "end": {"dateTime": "END_ISO_LOCAL", "timeZone": "America/New_York"}, "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"], "attendees": [{"email": "team@company.com"}]}'`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. Create recurring event: `gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "Weekly Standup", "start": {"dateTime": "2024-03-18T09:00:00", "timeZone": "America/New_York"}, "end": {"dateTime": "2024-03-18T09:30:00", "timeZone": "America/New_York"}, "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"], "attendees": [{"email": "team@company.com"}]}'`
1. Create recurring event: `gws calendar events insert --params '{"calendarId": "primary"}' --json '{"summary": "Weekly Standup", "start": {"dateTime": "START_ISO_LOCAL", "timeZone": "America/New_York"}, "end": {"dateTime": "END_ISO_LOCAL", "timeZone": "America/New_York"}, "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"], "attendees": [{"email": "team@company.com"}]}'`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-schedule-recurring-event/SKILL.md` at line 22, The example
recurring event command hardcodes a past start date/time ("2024-03-18T09:00:00")
which can confuse users; update the SKILL.md example (the gws calendar events
insert command and its JSON payload) to use either a placeholder (e.g.,
"<ISO_DATETIME_FUTURE>") or a clearly future-relative example (e.g., start date
computed relative to now) and note the expectation for an ISO 8601 datetime and
timezone in the "start"/"end" fields so readers can substitute a current future
date when testing.

Comment on lines +22 to +24
1. Get event attendees: `gws calendar events get --params '{"calendarId": "primary", "eventId": "EVENT_ID"}'`
2. Share file with each attendee: `gws drive permissions create --params '{"fileId": "FILE_ID"}' --json '{"role": "reader", "type": "user", "emailAddress": "attendee@company.com"}'`
3. Verify sharing: `gws drive permissions list --params '{"fileId": "FILE_ID"}' --format table`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify iteration over multiple attendees.

Step 2 shows a single command with a hardcoded email address (attendee@company.com), but the recipe description states it shares with "all attendees" and Step 2's description says "each attendee." This may confuse users who are unclear about how to extract the attendee list from Step 1's output and iterate the permission-creation command for each one. Consider adding a note that Step 2 should be repeated for each attendee retrieved in Step 1, or provide an example of extracting attendee emails from the event JSON.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gws/skills/recipe-share-event-materials/SKILL.md` around lines 22 - 24, Step
2 is ambiguous: clarify that the gws drive permissions create command must be
executed for each attendee returned by gws calendar events get; instruct the
author to add a short note explaining how to extract attendee emails from the
event JSON (from the attendees array returned by gws calendar events get with
EVENT_ID) and that the gws drive permissions create call (using FILE_ID) should
be repeated for each attendee.email (or provide a simple shell/scripting example
outline) so readers understand how to iterate over all attendees.

Use mktemp -d for safe temp directory creation and ${:?} guard on
cleanup. Default metadata.openclaw.requires.skills to [] when missing.
Add .coderabbit.yaml to exclude vendored gws/skills/** from reviews.

Assisted-by: Claude:claude-opus-4-6
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.claude/skills/gws-sync.md (1)

15-18: Prefer automatic cleanup with an EXIT trap.

If the workflow exits before Step 8, the temp dir can be left behind. Register cleanup right after creation.

Suggested patch
 ### 1. Generate upstream skills
 
 ```bash
 GWS_TMP_DIR="$(mktemp -d)"
+trap 'rm -rf "${GWS_TMP_DIR:?}"' EXIT
 gws generate-skills --output-dir "$GWS_TMP_DIR"

@@

8. Cleanup

-bash -rm -rf "${GWS_TMP_DIR:?}" -
+Cleanup is handled automatically by the EXIT trap from Step 1.


</details>


Also applies to: 84-88

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.claude/skills/gws-sync.md around lines 15 - 18, After creating the
temporary directory with GWS_TMP_DIR="$(mktemp -d)" register an EXIT trap to
remove it (trap 'rm -rf "${GWS_TMP_DIR:?}"' EXIT) so the temp dir is always
cleaned if the workflow exits early; add this trap immediately after the mktemp
call in the section using GWS_TMP_DIR and remove the later manual rm -rf
"${GWS_TMP_DIR:?}" cleanup in Step 8 to avoid double-deletion.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.claude/skills/gws-sync.md:

  • Around line 15-18: After creating the temporary directory with
    GWS_TMP_DIR="$(mktemp -d)" register an EXIT trap to remove it (trap 'rm -rf
    "${GWS_TMP_DIR:?}"' EXIT) so the temp dir is always cleaned if the workflow
    exits early; add this trap immediately after the mktemp call in the section
    using GWS_TMP_DIR and remove the later manual rm -rf "${GWS_TMP_DIR:?}" cleanup
    in Step 8 to avoid double-deletion.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Repository: cblecker/coderabbit/.coderabbit.yaml

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `b94efbfc-4a3c-4873-b4f8-693a88972c9d`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 656d7a8e506bba7e0326d747af987dd4c494899f and 6b619bcba9f809f38452b53fbe966fbd489e5f30.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `.claude/skills/gws-sync.md`
* `.coderabbit.yaml`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@cblecker
Copy link
Owner Author

Addressed the two comments on our authored file (.claude/skills/gws-sync.md) in 6b619bc:

  • Hardened temp directory handling with mktemp -d and ${:?} cleanup guard
  • Added [] default fallback for metadata.openclaw.requires.skills

Also added .coderabbit.yaml to exclude gws/skills/** from future reviews — these are vendored upstream files generated by gws generate-skills and copied as-is. The remaining 25 review comments all target these vendored files. Fixes for those should go upstream to googleworkspace/cli; local modifications would be overwritten on the next /gws-sync.

@cblecker cblecker merged commit 62ff102 into main Mar 18, 2026
8 checks passed
@cblecker cblecker deleted the feat/gws-plugin branch March 18, 2026 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant