Gmail No Send
Analysis
The code appears to omit Gmail sending, but it still stores a powerful Gmail OAuth token and can modify mail/drafts, so its “read-only/no-send” framing and account handling need careful review.
Findings (5)
Artifact-based informational review of SKILL.md, metadata, install specs, static scan signals, and capability signals. ClawScan does not execute the skill or run runtime probes.
Checks for instructions or behavior that redirect the agent, misuse tools, execute unexpected code, cascade across systems, exploit user trust, or continue outside the intended task.
description: Read-only Gmail CLI that cannot send email by design. Search, read, create drafts, update drafts, and archive messages
The same description labels the tool read-only while listing draft creation, draft updates, and archive actions, which are Gmail state changes.
def archive(self, message_id: str) -> Dict[str, Any]: ... body = {"removeLabelIds": ["INBOX"]} ... service.users().messages().modify(userId="me", id=message_id, body=body).execute()The archive command directly modifies Gmail labels for a message; the artifacts do not show a confirmation or approval step around this high-impact action.
dependencies = ["google-api-python-client", "google-auth-httplib2", "google-auth-oauthlib"]
The Python dependencies are not version-pinned, so future installs may resolve to different package versions.
Checks whether tool use, credentials, dependencies, identity, account access, or inter-agent boundaries are broader than the stated purpose.
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/gmail.compose", "https://www.googleapis.com/auth/gmail.modify", ...]; def load_credentials(): tp = token_path(); ... def save_credentials(creds: Credentials): ... token_path().write_text(creds.to_json())
The persisted OAuth token has Gmail read/compose/modify authority, and credential loading/saving uses a single token path rather than binding tokens to the --account value.
Checks for exposed credentials, poisoned memory or context, unclear communication boundaries, or sensitive data that could leave the user's control.
audit_log("search", {"account": self.account, "query": query, "max_results": max_results}); ... audit_log("draft.create", {"account": self.account, "to": to, "subject": subject})The local audit log records Gmail search queries and draft recipient/subject metadata, which can be sensitive even though logging is disclosed.
