소스 정보
- 저장소
- Sheldenshi/gini-agent
- 최근 소스 활동
- 2026년 6월 18일 19:34
- 감지된 SKILL.md 언어
- 영어
- 스타
- 671
- 포크
- 160
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/Sheldenshi/gini-agent --skill google-gmail명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
Move bytes between Gini upload space, external URLs, and workspace files. Used by every attachment / file-upload / file-download flow regardless of the target system (Linear, GitHub, S3, Notion, etc.).
Google Calendar via gws: list events, create, accept, find free time.
Google Docs via gws: read, append text, structured batch edits.
SOC 직업 분류 기준
| name | google-gmail |
| description | Gmail via gws: send, read, search, label, draft, reply, forward. |
| license | MIT |
| compatibility | macOS and Linux. Requires the `gws` CLI authenticated against a Google account with Gmail scopes. |
| metadata | {"gini":{"version":"1.2.0","author":"Gini","platforms":["macos","linux"],"prerequisites":{"commands":["gws"],"env":["GOOGLE_WORKSPACE_CLI_CLIENT_ID","GOOGLE_WORKSPACE_CLI_CLIENT_SECRET"]},"requires":{"credentials":["google-workspace-oauth"]}}} |
Use gws gmail to read, search, send, reply, forward, draft, label, and triage Gmail directly from the terminal. The CLI wraps the Gmail v1 API and produces structured JSON, so it composes cleanly with jq and other shell tooling.
gws writes its JSON to stdout and a Using keyring backend: keyring preamble (plus any warnings) to stderr. terminal_exec already shows the two streams as separate blocks, so on its own the preamble is harmless — but the moment you pipe gws into a JSON parser you must strip stderr first, or the preamble lands on the JSON and the parse throws:
gws ... 2>/dev/null | jq ... # correct: stderr dropped before the pipe
gws ... 2>/dev/null | python3 -c 'import sys,json; json.load(sys.stdin)'
Never use 2>&1 when piping into a parser — it folds the preamble onto the JSON and breaks it. Do not pass --format text either; it is invalid (valid formats are json, table, yaml, csv), and the raw users.* API already defaults to JSON. When you just need the data and don't need to parse it yourself, prefer the curated +helpers, which print clean output. Note that 2>/dev/null also discards gws's own error messages, so if a command returns empty or unexpected output, re-run it without the redirect (or check the exit code) to see the actual error.
gws installed and authenticated. If gws is not on PATH OR gws auth status reports no authenticated user, do NOT silently call setup. Instead, in a single short reply to the user:
read_skill with name google-workspace-setup and run that skill's onboarding flow turn-by-turn. If they say no or ask to defer, acknowledge briefly and stop — do not retry the original request.gws gmail ... call fails mid-task with command not found / ENOENT, HTTP 401, "no credentials", or "scope required". Don't report the failure as a dead end — surface the missing prerequisite and ask if the user wants to set it up before moving on.gmail.readonlygmail.sendgmail.modify — upstream helpers fetch the original message to thread In-Reply-To / References headers, which gmail.send alone cannot dogmail.modify (or https://mail.google.com/ for full access including permanent delete)+watch): gmail.modify AND https://www.googleapis.com/auth/pubsub — Cloud Pub/Sub is a separate Google API and its scope must be granted alongside the Gmail scopeThe connected Google accounts (each with its tag, email, and config dir) are listed in your system context under "Connected Google accounts". To target a specific account, prefix the command with its config dir:
GOOGLE_WORKSPACE_CLI_CONFIG_DIR="<configDir>" gws gmail +triage
Selection rule: one account connected → just use it. Two or more:
gws call per config dir) and aggregate, labeling each result by its tag and email. Don't pick just one, and don't ask — the user wants the whole picture across accounts.If no accounts are connected yet, fall back to the setup flow in Prerequisites (read_skill with google-workspace-setup).
gws gmail +watch).memory tool, not email-to-self.apple-reminders.apple-notes or obsidian.google-calendar (a Gmail invite is still a Calendar event).The Gmail surface in gws is split into auto-generated API methods (gws gmail users messages list, gws gmail users labels create, …) plus a small set of curated helpers (+send, +reply, +read, +triage, …) that handle MIME encoding, threading, and base64 for you. Prefer the helpers for everyday tasks. The raw API is rooted at the users resource — every --params JSON must include "userId": "me" (or another delegated address).
gws gmail +send --to alice@example.com --subject 'Hello' --body 'Hi Alice!'
# CC, BCC, alias send-from
gws gmail +send --to alice@example.com --cc bob@example.com \
--subject 'Status' --body 'See below.' --from alias@example.com
# Attachments (repeatable, 25 MB total)
gws gmail +send --to alice@example.com --subject 'Report' \
--body 'See attached.' -a report.pdf -a notes.txt
# HTML body
gws gmail +send --to alice@example.com --subject 'Update' \
--body '<b>Bold</b> text' --html
# Save as draft instead of sending
gws gmail +send --to alice@example.com --subject 'Draft' --body 'WIP' --draft
After you save a draft (--draft), show it to the user inline so they can read it right in the chat — never tell them to open Gmail and search for it. Lead with one short sentence, then render the draft as a fenced email-draft block: optional To: / Cc: / Subject: header lines, a blank line, then the exact body you saved.
I drafted this reply for you:
```email-draft
To: support@plaud.ai
Subject: Follow-up on your Request #527545
Hi there,
I still haven't received the package, and the delivery photo shows it was left
inside a publicly accessible gate. Could you reopen the case and coordinate a
replacement or refund?
Thanks
```
Use the same recipient, subject, and body you passed to gws gmail +send … --draft so the card matches the saved draft. The app renders the email-draft block as a draft card; any non-rendering client degrades it to a readable code block.
gws gmail +read --id <MESSAGE_ID> # plain-text body
gws gmail +read --id <MESSAGE_ID> --headers # include From/To/Subject/Date
gws gmail +read --id <MESSAGE_ID> --format json 2>/dev/null | jq '.body'
gws gmail +read --id <MESSAGE_ID> --html # HTML body instead of text
gws gmail users messages list accepts standard Gmail search operators via the q param (from:, to:, subject:, label:, is:unread, has:attachment, newer_than:7d, etc.).
gws gmail users messages list --params '{"userId":"me","q":"from:alice@example.com is:unread","maxResults":20}'
gws gmail users messages list --params '{"userId":"me","q":"label:invoices newer_than:30d"}' --page-all
gws gmail +triage # curated unread inbox digest
gws gmail +reply --message-id <MESSAGE_ID> --body 'Thanks — will follow up.'
gws gmail +reply-all --message-id <MESSAGE_ID> --body 'Looping in the team.'
gws gmail +forward --message-id <MESSAGE_ID> --to charlie@example.com \
--body 'FYI from the thread below.'
The helpers preserve In-Reply-To and References headers so the reply lands inside the original thread.
gws gmail users labels list --params '{"userId":"me"}'
gws gmail users labels create --params '{"userId":"me"}' \
--json '{"name":"Receipts","labelListVisibility":"labelShow"}'
gws gmail users messages modify --params '{"userId":"me","id":"<MESSAGE_ID>"}' \
--json '{"addLabelIds":["Label_123"],"removeLabelIds":["INBOX"]}'
gws gmail users drafts list --params '{"userId":"me"}'
gws gmail users drafts get --params '{"userId":"me","id":"<DRAFT_ID>"}'
gws gmail +watch # streams new messages as NDJSON (one JSON object per line)
+send, +reply, +reply-all, +forward, messages.send, and drafts.send put a message in the user's voice in front of someone else — an irreversible, third-party-facing action, so the global request_confirmation rule governs and the terminal_exec approval gate is NOT the safety net here (it doesn't fire when gws is auto-approved). When the user dictated this message and told you to send it ("email alice@acme.com that I'll be 10 min late"), execute directly. When you composed the reply yourself or the user only delegated the outcome ("get back to her," "handle this thread"), call request_confirmation with the drafted message and send only on a confirm — even when auto-approved. Don't add a redundant prose "shall I send?"; use request_confirmation. Ask one clarifying question when the command is ambiguous — multiple "alice" matches in the address book, more than one thread could be the reply target, or the user named a verb but no recipient. The message body is the user's voice to someone else, not a parameter you fill in: write it only from what they told you to say or what's unmistakable from the thread. When you'd be inventing the substance — they named a recipient or thread but not what to say — ask what they want to convey before drafting; don't compose a position and present it as theirs.+send, +reply, +read, +triage) over the raw gws gmail <resource> <method> surface — they handle MIME, base64, threading, and HTML-to-text conversion automatically.+reply / +reply-all so the thread stays intact. Building a new message with +send and pasting in the prior subject does not thread correctly.gmail.readonly covers +read / +triage and any messages.list/get call; gmail.send covers a brand-new +send only; gmail.modify is required for +reply, +reply-all, +forward, labels, and drafts because those helpers must fetch the original message or mutate its state; +watch requires AND because the upstream helper requests both tokens (Pub/Sub is a separate Google API). If the user only granted a narrower scope at setup, never silently call a verb that needs a wider one — direct them back to to widen scopes.For flags not shown here, run gws gmail --help or gws gmail <verb> --help (e.g. gws gmail +send --help).
gmail.modifyhttps://www.googleapis.com/auth/pubsubgoogle-workspace-setup@gmail.com account. Google throttles or suspends accounts that look like bulk senders. Use a transactional provider for newsletters or anything addressed to more than a handful of recipients.google-drive and send the share link instead.email-draft fenced block (see "Show a saved draft to the user") instead of pointing them at Gmail. The user should be able to read the draft without leaving the app.