This is a CLI tool that fetches Google Docs via the Google Docs API and converts them to Markdown with YAML frontmatter. It uses OAuth2 authentication with token caching for user authorization.
Primary Use Case: This tool is designed for AI coding agents to fetch Google Docs documentation and convert it to markdown for analysis, context gathering, or integration into AI workflows. The clean markdown output and stdout design make it ideal for piping into AI systems.
# Build the CLI binary
go build -o gdocs-cli cmd/gdocs-cli/main.go
# Run all tests
go test ./...
# Run tests with coverage
go test ./... -cover
# Run tests with verbose output
go test ./... -v
# Run specific package tests
go test ./internal/gdocs -v
go test ./internal/markdown -v
go test ./internal/auth -v
go test ./cmd/gdocs-cli -v
# Run a single test
go test ./internal/gdocs -run TestExtractDocumentID -v
# Clean up dependencies
go mod tidyUser Input (URL + credentials)
↓
main.go (CLI parsing & orchestration)
↓
auth/oauth.go (OAuth2 flow & token caching)
↓
gdocs/client.go (Google Docs API client)
↓
gdocs/url.go (Extract doc ID from URL)
↓
client.FetchDocument() → Returns *docs.Document
↓
markdown/converter.go (Main orchestrator)
↓
├→ markdown/frontmatter.go (YAML metadata)
├→ markdown/structure.go (headings, lists, tables)
└→ markdown/text.go (bold, italic, links)
↓
Markdown output to stdout
-
OAuth2 Token Caching: Tokens are cached at
~/.config/gdocs-cli/token.jsonto avoid repeated browser authentication. Theauthpackage handles both initial authentication and automatic token refresh. -
Structural Element Processing: Google Docs API returns a tree of
StructuralElementobjects (paragraphs, tables, etc.). The converter iterates throughdoc.Body.Contentand dispatches to specialized functions based on element type. -
Text Style Application: Text formatting is applied at the
TextRunlevel. Each paragraph contains multipleParagraphElementobjects, which may containTextRunobjects withTextStyleproperties (bold, italic, link, etc.). -
List Handling: Lists in Google Docs API are complex - each list item is a paragraph with a
Bulletfield containingListIdandNestingLevel. The converter uses indentation (2 spaces per level) to represent nesting. -
Clean Flag: The
--cleanflag suppresses logs by settinglog.SetOutput(io.Discard). Errors still go to stderr, but informational logs are silenced.
cmd/gdocs-cli: CLI entry point, flag parsing, orchestration. No business logic here.internal/auth: OAuth2 flow, token caching, credential loading. Handles all authentication concerns.internal/gdocs: Google Docs API client wrapper and URL parsing. Fetches documents from the API.internal/markdown: Conversion logic split into:converter.go: Main orchestrator that drives the conversionfrontmatter.go: YAML frontmatter generationtext.go: Text-level formatting (bold, italic, links)structure.go: Document structure (headings, lists, tables, paragraphs)
Understanding the Google Docs API structure is critical:
docs.Document
├─ Title (string)
├─ Body
│ └─ Content []StructuralElement
│ ├─ Paragraph
│ │ ├─ Elements []ParagraphElement
│ │ │ └─ TextRun
│ │ │ ├─ Content (string)
│ │ │ └─ TextStyle (Bold, Italic, Link, etc.)
│ │ ├─ ParagraphStyle (NamedStyleType: HEADING_1, NORMAL_TEXT, etc.)
│ │ └─ Bullet (ListId, NestingLevel)
│ └─ Table
│ └─ TableRows []TableRow
│ └─ TableCells []TableCell
│ └─ Content []StructuralElement (recursive)
└─ Lists map[string]*List (list metadata by ListId)
When adding support for new Google Docs features:
- Check the
StructuralElementtype inconverter.go - Add a new handler function in
structure.goif it's structural - Add formatting logic in
text.goif it's text-level - Update tests to cover the new feature
- Unit tests (
*_test.goin each package): Test individual functions with mocked Google Docs API structures - Integration tests (
cmd/gdocs-cli/main_test.go): Build and execute the binary as a subprocess to test end-to-end flows - Integration tests don't show in coverage reports because they run the binary externally, but they ensure the CLI works correctly from a user perspective
--url: Google Docs URL (required for normal operation)--config: Path to OAuth2 credentials JSON (defaults to~/.config/gdocs-cli/config.json)--init: Initialize OAuth and save token (doesn't require --url)--clean: Suppress all logs, only output markdown--instruction: Print integration instructions for AI coding agents
Default Config Path: If --config is not provided, the tool automatically looks for credentials at ~/.config/gdocs-cli/config.json. This is particularly useful for AI agents that can set up credentials once and then use the tool without specifying the path on every invocation.
The --clean flag is particularly important for AI agents and scripting - it ensures only markdown goes to stdout, making it easy to pipe the output directly into AI systems or other tools.
OAuth2 tokens expire. The auth package uses oauth2.TokenSource which automatically refreshes tokens when they expire. The refreshed token is saved back to the cache file. If refresh fails (e.g., token revoked), the user must re-authenticate with --init.
Errors are wrapped with context using fmt.Errorf("context: %w", err) to provide clear error chains. The main function prints errors to stderr and exits with non-zero codes. When adding new features, maintain this pattern for user-friendly error messages.