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.1.0.tar.gz (16.7 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.1.0-py3-none-any.whl (15.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for md_to_gdocs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c79b79c8164b4ea0565836fa835195c432837b961bdd14b218c95f6e2d89fe89
MD5 b4beb08bb158f56f801eb327837056b9
BLAKE2b-256 b30ec0bdd5a8eab9de52be529171a37b1612add24f65a2981294edb8e86089ee

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for md_to_gdocs-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e761b371d833592a830c3436786e96d215822de276f68d5fd75401a5777874b8
MD5 1c200da507a8fa937da461562d2406c8
BLAKE2b-256 f381e733a34bf66704176b55747062f53ca6ebf3a60b6a834b657b4585cdc245

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