From ai-brain-starter
Ingests recent Gmail messages matching a label or query into the vault as queryable markdown files in External Inputs/Gmail/<label>/<date>.md. Truncates bodies to 500 chars for PII limits. Use for /ingest-gmail <label-or-query> [--days N] or sync requests.
npx claudepluginhub adelaidasofia/ai-brain-starterThis skill uses the workspace's default tool permissions.
Ingests recent Gmail messages (matching a label or a free-text Gmail query) into the vault as markdown the graphify pipeline can read and the rest of the AI Brain Starter substrate (decision log, session-close cascade, hooks) can act on.
Executes Gmail triage from vault reports: archive, delete, label, star, unsubscribe emails. Drafts replies interactively or autonomously using /gmail, /gmail draft, /gmail auto-draft.
Interact with Gmail via Python CLI: search/read/send emails, create drafts, manage labels (read/archive/star). Standalone OAuth for Google Workspace accounts.
Accesses Gmail via CLI with 1Password OAuth to read emails, search inbox, export messages, list threads, and create drafts. Triggers on gmail/email mentions.
Share bugs, ideas, or general feedback.
Ingests recent Gmail messages (matching a label or a free-text Gmail query) into the vault as markdown the graphify pipeline can read and the rest of the AI Brain Starter substrate (decision log, session-close cascade, hooks) can act on.
This is one of a small family of ingestion connectors (slack, linear, gmail). Adding the next external source means writing a new normalizer, not a new architecture.
/ingest-gmail <label-or-query> (with or without --days N)Do NOT use for:
gmail_send)gmail_reply)gmail_read)Gmail content is the highest-PII surface in the vault. A typical inbox carries personal email addresses, phone numbers, full names, contract numbers, billing details, internal company memos, and confidential business discussion. Every ingestion writes a copy of that data into the vault.
Operator obligations:
humanizer and extract-rules-from-vault skills have scrub helpers; use them.If any of these obligations is unclear, do not run the skill. Ask first.
gmail_labels_list) or a free-text Gmail query (anything containing search operators like from:, to:, subject:, is:, after:, before:).gmail_search. Apply the day window via after:YYYY/MM/DD in the query string.gmail_read (without keep_html) to get the plain-text body.## per message, body truncated to 500 chars).External Inputs/Gmail/<scope>/<YYYY-MM-DD>.md where <scope> is the label name (slugified) or query-<sha8> if the input was a free-text query.[...truncated]The skill is a thin orchestrator. The actual ingestion runs in Python at ${SKILL_ROOT}/ingest.py. The skill assembles the Google Workspace MCP tool calls, hands the raw payloads to ingest.py, and the script does the normalization, file write, and frontmatter.
When invoked:
--days N (optional, default 7).from:, to:, subject:, is:, has:, label:, after:, before:, in:), treat it as a free-text query. Otherwise treat it as a label name.gmail_labels_list and verify the label exists. If not, report "label not found" and stop.label:<label-name> after:YYYY/MM/DD. For a free-text query, append after:YYYY/MM/DD to the user's query.gmail_search with the query and limit: 50 (the per-page max). Do not paginate beyond this; the skill is for a daily snapshot, not a full archive scan.gmail_read with that message ID.ingest.py as JSON on stdin.ingest.py writes the vault file, truncates each body to 500 chars, and prints a summary.The vault file at External Inputs/Gmail/<scope>/<YYYY-MM-DD>.md has frontmatter:
---
type: external-input
source: gmail
label_or_query: <verbatim string>
scope_kind: label | query
date_range: <YYYY-MM-DD>..<YYYY-MM-DD>
message_count: <int>
ingested_at: <ISO 8601 timestamp>
entity_ids:
gmail:
- <gmail-message-id-1>
- <gmail-message-id-2>
---
Body is chronological. Each message is a ## YYYY-MM-DD HH:MM <sender> section with the subject as the first line of the body, then the truncated body excerpt. Long bodies end with [...truncated].
Re-running /ingest-gmail <scope> --days N on the same calendar day overwrites the same vault file. No append. The entity_ids.gmail array reflects exactly the messages in the current window.
A successful run produces:
External Inputs/Gmail/<scope>/<date>.mdWrote N message(s) to <path>.If the scope resolves but contains no matching messages in the window, write the file anyway with message_count: 0 so re-runs are still idempotent and the absence is recorded.
ingest.py does not require the MCP. The MCP calls happen at the orchestration layer. If the LLM cannot reach the MCP, surface that error to the user, do not write a stub file.message_count: 0._(body unavailable)_ for that message; keep the rest of the file intact.