Install
$ agentstack add skill-jtsternberg-claude-plugins-google-doc-to-md ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Google Doc to Markdown
Download Google Docs as local markdown files. The Google Drive API natively supports text/markdown as an export format, so no external conversion tools are needed — the only variable is which account can authenticate to reach the doc.
Source routing
gws only authenticates your personal Google account. If the doc lives in an account gws can't reach (e.g. a work account), route through the next rung instead of giving up. Try rungs in order; only read/run the next rung on fallthrough — don't front-load setup you may not need.
Rung 1 — gws (default, unchanged)
Use the existing workflow below. This is the primary path whenever gws can authenticate to the doc's account.
Fall through to rung 2 if gws auth status fails, or the export/metadata call 403s/404s for the doc (wrong account, not the auth-expired case — that's a gws auth login fix, not a routing fallthrough).
Rung 2 — gcloud ADC (optional, only if configured)
Same clean native text/markdown export as rung 1 — same server-side exporter — just authenticated via gcloud Application Default Credentials instead of gws. Use this when the doc's account has ADC set up but not gws (e.g. a work account you've done gcloud auth application-default login for).
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/adc-check.sh" # fast preflight; exit 0 = configured
bash "$SKILL_DIR/scripts/adc-export.sh" [output.md]
If adc-check.sh fails, it prints an actionable one-line reason. Only then read [references/adc-setup.md](references/adc-setup.md) for the full gcloud setup steps — don't load it up front. If ADC isn't configured and setting it up isn't worth it right now, fall through to rung 3.
> Escaping note (all rungs): Drive's native exporter also > backslash-escapes markdown-significant punctuation that appears as > literal text in the doc (Catch up\!, \#123, (Q2 2026\)) — verified > live 2026-07-16 on a real doc. It's valid CommonMark, but if the raw > markdown is for human editing, the same de-escaper works on any rung. Codex: > this path resolves under Claude Code; substitute the directory containing this > SKILL.md in SKILL_DIR="${CLAUDE_SKILL_DIR}"; python3 "$SKILL_DIR/scripts/deescape.py" in.md out.md. > Docs that round-tripped from markdown import export clean; docs with > hand-typed punctuation don't. The connector rung always needs it.
Rung 3 — claude.ai Google Drive connector (zero setup, needs de-escaping)
Use when neither gws nor ADC can reach the doc's account, and the mcp__claude_ai_Google_Drive__* tools are available in this session (e.g. a work account added only via the Claude.ai connector). Verified live (2026-07-14, see the smoke-test notes): the connector's markdown export is backslash-escaped (\#, \[, \*, …) — there is no clean-export mode to prefer, a de-escape pass is required.
- Resolve the doc ID (same URL pattern as rung 1: the segment after
/document/d/ up to the next /, ?, or #).
- Call
mcp__claude_ai_Google_Drive__get_file_metadatawithfileIdto
confirm access and get the title.
- Call
mcp__claude_ai_Google_Drive__download_file_contentwith
fileId and exportMimeType: "text/markdown". Base64-decode the returned content (e.g. python3 -c "import sys,base64; sys.stdout.write(base64.b64decode(sys.argv[1]).decode('utf-8'))" "$B64" or write to a temp file and base64 -d).
- De-escape it:
``bash # Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md. SKILL_DIR="${CLAUDE_SKILL_DIR}" python3 "$SKILL_DIR/scripts/deescape.py" TEMP_INPUT.md CLEANED.md ``
- Write
CLEANED.md's content to the output file (same filename-derivation
rules as rung 1).
Known limitation: a literal backslash in the source prose immediately followed by punctuation (e.g. C:\*.txt) is indistinguishable from a connector-introduced escape and will also get unescaped. Low risk for prose docs; call it out if the source doc is code-heavy or path-heavy.
If none of the three rungs can reach the doc, fail with a clear message naming which rungs were tried and why each failed — don't silently give up after rung 1.
Prerequisites (rung 1)
```!
Codex: this path resolves under Claude Code; substitute the directory containing this plugin.
PLUGINROOT="${CLAUDEPLUGINROOT}" bash "$PLUGINROOT/scripts/auth-preflight.sh"
## Task (rung 1)
Run the entrypoint script, passing all arguments through:
```bash
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" $ARGUMENTS
If no arguments were provided, ask the user for the Google Doc URL or ID and optionally the output file path.
Script Details
Downloading a Google Doc
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_ID_OR_URL
With a custom output path:
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_ID_OR_URL ./output.md
With --title flag to use the doc's title as the filename:
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_ID_OR_URL --title
How It Works
- Extracts the doc ID from a URL if a full URL is provided
- Fetches the document title from Google Drive metadata
- Exports the doc as markdown via
gws drive files exportwith
mimeType: text/markdown (native Drive API support)
- Writes the result to the output file
Extracting a Doc ID
The doc ID is the long string in a Google Docs URL: https://docs.google.com/document/d/DOC_ID_HERE/edit
Output Filename
When no output path is given:
- If
--titleis set, derives the filename from the Google Doc title
(lowercased, spaces to hyphens, .md extension)
- Otherwise defaults to
.mdin the current directory
Export Size Limit
Google limits exported content from files.export to 10 MB.
Working with Native Doc Tabs
List a doc's tabs (id, index, title — indented by nesting):
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_ID --list-tabs
Export a single tab as markdown (basic fidelity: headings, bold/italic, links, lists, tables):
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_ID out.md --tab "Tab Title"
Note: the default (no --tab) Drive export flattens ALL tabs into one markdown file with each tab's title as a heading — fine for single-tab docs, confusing for multi-tab ones. Use --list-tabs first when unsure.
Batch Downloads
When downloading multiple docs, run in parallel:
# Codex: this path resolves under Claude Code; substitute the directory containing this SKILL.md.
SKILL_DIR="${CLAUDE_SKILL_DIR}"
bash "$SKILL_DIR/scripts/download.sh" DOC_URL_1 ./doc1.md &
bash "$SKILL_DIR/scripts/download.sh" DOC_URL_2 ./doc2.md &
wait
Additional Resources
If the bundled scripts are unavailable, see [MANUAL.md](references/MANUAL.md) for the step-by-step manual workflow.
Troubleshooting
Auth expired: Run gws auth login to re-authenticate. Wrong account: Run gws auth status to check which account is active. Account mismatch: If the doc belongs to a different Google account, the script will tell you which account you're authenticated as and suggest sharing or switching accounts. Run gws auth status to check. Empty output: The doc may be empty or the export may have failed — check stderr for error messages.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jtsternberg
- Source: jtsternberg/claude-plugins
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.