Skip to main content

Convert markdown to Google Docs with formatting support

Project description

md-to-gdocs

Convert markdown files to Google Docs with formatting support. Both CLI tool and Python library.

Features

  • CLI and Library: Use as command-line tool or Python library
  • Formatting Support: Headers, bold, italic, links, bullet lists
  • Flexible Operations: Create, append, insert at specific positions
  • Dry Run Mode: Preview changes before applying
  • JSON Output: Automation-friendly output format

Installation

Local Development

cd /path/to/markdown-to-google-doc
uv sync

From PyPI

pip install md-to-gdocs
# or with uv
uv pip install md-to-gdocs

Prerequisites

Google Authentication

You need a google_token.json file with Google OAuth2 credentials.

Token File Locations (checked in order):

  1. ./google_token.json (current directory - highest priority)
  2. ~/.claude/google_token.json (Claude directory)
  3. Custom path via --token flag

How to Generate Token:

Option 1: Using Claude Code

/google-auth  # Creates ~/.claude/google_token.json

Option 2: Manual Setup (for standalone use)

  1. Go to Google Cloud Console
  2. Create a project or select existing one
  3. Enable Google Docs API
  4. Create OAuth 2.0 credentials (Desktop app)
  5. Download credentials and save as google_token.json
  6. Place in current directory or ~/.claude/

Required Scope: https://www.googleapis.com/auth/documents

CLI Usage

Create New Document

# Basic usage (title derived from filename)
md-to-gdocs create README.md

# With custom title
md-to-gdocs create README.md --title "My Documentation"

# With custom token path
md-to-gdocs create README.md --token /path/to/google_token.json

# Dry run (preview without creating)
md-to-gdocs create README.md --dry-run

# JSON output (for scripting)
md-to-gdocs create README.md --output-json

Append to Existing Document

# Append markdown to end of document
md-to-gdocs append 1abc234def567 changelog.md

# With dry run
md-to-gdocs append 1abc234def567 changelog.md --dry-run

Insert at Specific Index

# Insert at character index 1234
md-to-gdocs update-index 1abc234def567 section.md 1234

# Use --dry-run to preview
md-to-gdocs update-index 1abc234def567 section.md 1234 --dry-run

Find Text (Get Character Indices)

# Find text and get indices (JSON output by default)
md-to-gdocs find 1abc234def567 "Section Header"

# Human-readable output
md-to-gdocs find 1abc234def567 "Section Header" --no-output-json

Python Library Usage

Create Document

from md_to_gdocs import create_document

markdown_content = """
# Main Header

This is **bold** and *italic* text.

- List item 1
- List item 2
"""

result = create_document(
    markdown_content=markdown_content,
    title="My Documentation"
)

if result.success:
    print(f"Created: {result.doc_url}")
    print(f"Doc ID: {result.doc_id}")
else:
    print(f"Error: {result.error}")

Append to Document

from md_to_gdocs import append_to_document

result = append_to_document(
    doc_id="1abc234def567",
    markdown_content="## New Section\n\nNew content here."
)

if result.success:
    print("Content appended successfully")

Insert at Index

from md_to_gdocs import update_at_index

result = update_at_index(
    doc_id="1abc234def567",
    markdown_content="## Inserted Section",
    start_index=1234
)

Find Text

from md_to_gdocs import find_text

locations = find_text(
    doc_id="1abc234def567",
    search_text="Section Header"
)

for loc in locations:
    print(f"Found at: {loc.index} - {loc.end_index}")
    print(f"Context: {loc.context}")

Dry Run Mode

result = create_document(
    markdown_content="# Test",
    title="Test Doc",
    dry_run=True
)

if result.dry_run:
    print(f"Would execute {len(result.requests)} API requests")
    print("Requests:", result.requests)

Supported Markdown Syntax

Headers

# H1 Header
## H2 Header
### H3 Header

Inline Formatting

**bold text**
*italic text*
***bold and italic***
[link text](https://example.com)

Lists

- Bullet item 1
- Bullet item 2

* Also works with asterisks
* Another item

Paragraphs

Regular text paragraphs are preserved. Blank lines create spacing.

Finding Document IDs

Google Doc IDs are in the URL:

https://docs.google.com/document/d/1abc234def567/edit
                                   ^^^^^^^^^^^^^^
                                   This is the doc_id

Workflow: Replace Section

To replace content between markers:

  1. Add HTML comments as markers in your Google Doc:

    <!-- START_SECTION -->
    Old content here
    <!-- END_SECTION -->
    
  2. Find the marker positions:

    md-to-gdocs find 1abc234def567 "<!-- START_SECTION -->"
    # Returns: index: 100, end_index: 125
    
    md-to-gdocs find 1abc234def567 "<!-- END_SECTION -->"
    # Returns: index: 500, end_index: 523
    
  3. Use the indices to insert new content (Phase 2 feature)

Error Handling

Authentication Errors

Error: Token file not found. Searched:
  - ./google_token.json
  - ~/.claude/google_token.json

Solution:

  • Place google_token.json in current directory or ~/.claude/
  • Or use --token flag to specify custom path
  • Generate token using /google-auth (Claude Code) or Google Cloud Console

Document Not Found

Error: Document 1abc234def567 not found

Solution: Check the document ID. Ensure you have access to the document.

Invalid Token

Error: Invalid credentials. Please run /google-auth skill to re-authenticate.

Solution: Token may be expired. Re-run /google-auth.

Development

Setup

# Clone and install dependencies
cd /Users/kprice/repos/misc/kj/markdown-to-google-doc
uv sync

# Install dev dependencies
uv sync --dev

Run Tests

# Run all tests with coverage
uv run pytest

# Run specific test file
uv run pytest tests/test_parsers.py

# Run with verbose output
uv run pytest -v

Code Quality

# Format code
uv run black src/ tests/

# Type checking
uv run mypy src/

Project Structure

markdown-to-google-doc/
├── src/md_to_gdocs/
│   ├── __init__.py          # Public API exports
│   ├── cli.py               # Typer CLI commands
│   ├── core.py              # Core library functions
│   ├── auth.py              # Google OAuth handling
│   ├── api.py               # Google Docs API operations
│   ├── models.py            # Data classes
│   ├── exceptions.py        # Custom exceptions
│   └── parsers/
│       ├── __init__.py
│       └── custom.py        # Markdown parser
└── tests/
    ├── conftest.py          # Pytest fixtures
    ├── test_parsers.py      # Parser tests
    ├── test_api.py          # API tests
    ├── test_core.py         # Core tests
    └── test_cli.py          # CLI tests

Roadmap

Phase 1 (Current - MVP)

  • ✅ Basic markdown parsing (headers, bold, italic, lists, links)
  • ✅ CLI commands (create, append, update-index, find)
  • ✅ Python library API
  • ✅ Dry run mode
  • ✅ Comprehensive tests

Phase 2 (Next)

  • ⏳ Section management (replace, delete between markers)
  • ⏳ Index-based section operations
  • ⏳ Enhanced text search

Phase 3 (Future)

  • ⏳ CI/CD pipeline
  • ⏳ Advanced markdown features (tables, code blocks)
  • ⏳ Alternative parser options (mistune)

Claude Code Integration

Want to use this as a Claude Code skill for automated documentation workflows?

See SKILL_CREATION.md for complete instructions on:

  • Converting this library into a reusable Claude skill
  • Usage patterns and workflow examples
  • Integration with /google-auth and other skills
  • Automated documentation publishing workflows

Contributing

This is currently a personal project. Contributions welcome after PyPI publication.

License

MIT License - see LICENSE file for details

Author

KJ Price

Acknowledgments

  • Parser design inspired by ai-book project
  • Google Docs API patterns from gdocs_editor.py
  • Built with: Typer, Rich, Google API Python Client

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

md_to_gdocs-0.2.0.tar.gz (31.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

md_to_gdocs-0.2.0-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file md_to_gdocs-0.2.0.tar.gz.

File metadata

  • Download URL: md_to_gdocs-0.2.0.tar.gz
  • Upload date:
  • Size: 31.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.28

File hashes

Hashes for md_to_gdocs-0.2.0.tar.gz
Algorithm Hash digest
SHA256 bfc0681d3dfc2ab3b99b0b123e15b74c9e4165688f1a0dda1ddee746c351e427
MD5 dc9783818a8a5e8f977e8778b38702bc
BLAKE2b-256 7c6ea5d2b6540a3555884152dfacd36a6497c9ae3bd59b85e43029b6e3ee0cc2

See more details on using hashes here.

File details

Details for the file md_to_gdocs-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for md_to_gdocs-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb5fa0355bb84ae7925b34d2936d654a027beed9e7b6e1c01d41ee440f87d73b
MD5 d7621ad6c7d1d711b7edd712038cc4d2
BLAKE2b-256 0937bafa1e72755ef25ff0ba2668d22d471f6e01041e715c61f36c366296c617

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page