google-docs
The google-docs skill enables reading, appending text to, and performing structured batch edits on Google Docs content via the gws command-line tool. Use it when you need to create blank documents, retrieve existing document text, add content to the end of a document, or execute multiple API operations against Google Docs, while delegating file-level operations like sharing and moving to google-drive instead.
git clone --depth 1 https://github.com/Lilac-Labs/gini-agent /tmp/google-docs && cp -r /tmp/google-docs/skills/google/google-docs ~/.claude/skills/google-docsSKILL.md
# Google Docs
Use `gws docs` to create blank documents, read existing document content, append text, and run structured batch updates against the Docs v1 API. This is the **content** surface for Google Docs — for the file as an object (sharing, copying, moving, trashing) use `google-drive` instead.
## Prerequisites
- `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:
1. State plainly what's missing — e.g. "Google Workspace access isn't set up on this machine yet" or "your Google sign-in has expired."
2. Ask one sentence: "Want me to walk you through setting it up?" Wait for the user's answer.
3. If they say yes, call `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.
- Apply the same flow when any `gws docs ...` 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.
- OAuth scopes the user picked at login must cover the verbs the agent will use:
- Read and edit Docs: `docs`
- Find docs by title (or list recent docs) before reading: pair with `drive.readonly`
## Selecting a Google account
The 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:
```bash
GOOGLE_WORKSPACE_CLI_CONFIG_DIR="<configDir>" gws docs documents create --json '{"title":"Notes"}'
```
Selection rule: one account connected → just use it. Two or more:
- The user named or clearly implied one account (a tag, an email, or unambiguous context) → use only that account.
- A read/lookup/search the user didn't tie to an account (e.g. listing events, searching mail, finding a doc) → run it against **every** connected account (one `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.
- A write (send, create, edit, delete) with no account named → ASK which account first; never guess.
If no accounts are connected yet, fall back to the setup flow in Prerequisites (`read_skill` with `google-workspace-setup`).
## When to Use
- The user asks Gini to read, draft, or edit the **body** of a Google Doc.
- Appending notes, meeting summaries, or AI-generated content to an existing doc.
- Creating a new blank doc as a starting point (then editing it with `+write` or `batchUpdate`).
- Running structured edits (insert text at index, replace all of a string, apply heading styles) via the `batchUpdate` API.
## When NOT to Use
- Sharing, moving, renaming, copying, trashing, or permission-managing a doc — use `google-drive` for the file-as-object surface.
- Spreadsheets — use Sheets (`gws sheets ...`), not Docs.
- Slide decks — use Slides (`gws slides ...`), not Docs.
- Personal cross-device notes — use `apple-notes` or `obsidian`; a Google Doc is overkill and slower to sync.
- Agent-internal scratch state — use the `memory` tool.
- Long-form Markdown the user maintains locally — keep it in the repo or vault. Docs is for content that needs collaborative editing or live sharing.
## Quick Reference
The Docs surface has only three top-level methods (`documents.get`, `documents.create`, `documents.batchUpdate`) plus a `+write` helper for the common "append text" case.
### Create a blank doc
```bash
gws docs documents create --json '{"title":"Weekly notes"}'
```
The response includes a `documentId` you will need for subsequent reads and writes. Other fields in the request (body, settings, …) are ignored by `documents.create` — set them with a follow-up `batchUpdate` call.
### Read a doc
```bash
gws docs documents get --params '{"documentId":"<DOC_ID>"}'
```
The response is the full structured Docs JSON tree (`body.content[]` of paragraph, table, sectionBreak, etc. elements). For a plain-text dump, pipe through `jq`:
```bash
gws docs documents get --params '{"documentId":"<DOC_ID>"}' \
| jq -r '.body.content[].paragraph?.elements[]?.textRun?.content // empty'
```
### Append text (helper)
```bash
gws docs +write --document <DOC_ID> --text 'Hello, world!'
gws docs +write --document <DOC_ID> --text "$(cat ./notes.md)"
```
`+write` inserts the given text at the end of the document body. For anything richer (bold, headings, bullet lists, replace-all, table insert) drop to `documents.batchUpdate`.
### Structured edits (`batchUpdate`)
The Docs API edits a doc as an ordered list of `requests`. Each request is one mutation. The whole batch is atomic — if any request is invalid, nothing is applied.
```bash
# Insert text at a specific index
gws docs documents batchUpdate \
--params '{"documentId":"<DOC_ID>"}' \
--json '{
"requests": [
{"insertText": {"location": {"index": 1}, "text": "Heading\n"}}
]
}'
# Replace every occurrence of a placeholder
gws docs documents batchUpdate \
--params '{"documentId":"<DOC_ID>"}' \
--json '{
"requests": [
{"replaceAllText": {
"containsText": {"text": "{{NAME}}", "matchCase": true},
"replaceText": "Alice"
}}
]
}'
# Apply heading style to a range
gws docs documents batchUpdate \
--params '{"documentId":"<DOC_ID>"}' \
--json '{
"requests": [
{"updateParagraphStyle": {
"range": {"startIndex": 1, "endIndex": 8},
"paragraphStyle": {"namedStyleType": "HEADING_1"},
"fields": "namedStyleType"
}}
]
}'
```
For schema details on each request type, inspect the method:
```bash
gws schema docs.documents.batchUpdate
```
### Find a doc by title before reading
Use `gDelegate coding work to Claude Code CLI for repository edits, reviews, and multi-turn implementation sessions.
Delegate coding work to the OpenAI Codex CLI for repository changes, reviews, and focused fixes.
Gini's self-knowledge: how Gini configures, extends, and operates on its own state via /api/* and registered tools. Load when the user asks Gini about its own capabilities or asks Gini to modify its own configuration.
Manage Apple Notes via memo CLI: create, search, edit.
Apple Reminders via remindctl: add, list, complete.
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.).
File a locally-captured, already-redacted Gini crash report as a GitHub issue, with the user's consent. Reads the pending crash queue and delegates the actual filing to the github-issues skill.
Create, search, triage, label, assign, comment on, and close GitHub issues using the gh CLI, with a curl REST fallback.