Read/write content and manage comments on Google Docs, Sheets, and Slides
Project description
csa-google-workspace
A Python library for managing comments and content on Google Docs, Sheets, and Slides, via the Google APIs. Comments are handled uniformly across all three file types (a single Drive API v3 concern); content read/write and Sheets comment→cell mapping are the variant, per-API parts.
It's designed to be embedded: a clean, typed Python surface for building AI tooling on top of Google Workspace — MCP servers, agent/LLM plugins, review bots, and automation services that need to read documents, triage and reply to comments, and write edits back. The Workspace(backend=…) seam (dependency injection / run-as-a-service) and the Backend protocol exist for exactly that; an MCP wrapper is a natural (out-of-scope-for-now) layer on top.
Status: feature-complete for its scoped roadmap and live-verified end-to-end against real Google. Shipped across Docs/Sheets/Slides: comment management, content read/write, Sheets comment→cell mapping, and Docs suggestions read. See
CHANGELOG.md; design + phased plans underdocs/superpowers/.
Install & test
pip install -e ".[dev]" # src/ layout, Python >=3.10
pytest -q # unit suite: no network, no credentials (in-memory FakeBackend)
ruff check src tests && mypy # lint + type-check (the CI `lint` job)
Everything above runs offline and gates CI. Two opt-in suites exercise real Google and are skipped unless their env vars are set:
# Live API suite — real Docs/Sheets/Slides/Drive. Needs OAuth client secrets; a cached token
# avoids re-consent, otherwise the first run opens a browser to log in:
CSA_GW_INTEGRATION=1 CSA_GW_CLIENT_SECRETS=path/to/client_secret.json pytest tests/integration/
# Interactive OAuth suite — the login flow itself (token caching, file permissions, read-only
# contract). Separate because it needs a human at a browser + touches the sensitive token:
CSA_GW_OAUTH=1 CSA_GW_CLIENT_SECRETS=path/to/client_secret.json pytest tests/oauth/
The client secret must be an installed/desktop-app OAuth client, and Drive, Docs, Sheets,
and Slides must be enabled in its Cloud project (a scoped token still 403s until each API is
enabled). client_secret.json and token*.json are gitignored — never commit them.
Usage
from csa_google_workspace import Workspace
ws = Workspace.from_credentials(my_google_creds) # BYO credentials (or .from_oauth("client_secret.json"))
doc = ws.open("https://docs.google.com/document/d/…/edit") # -> Doc | Sheet | Slides
# Comments — uniform across all three file types
for c in doc.comments.filter(resolved=False): # triage open comments
print(c.author.display_name, c.content)
c.reply("looking into it"); c.resolve()
doc.create_comment("Please review section 3")
# Content read + write (type-specific)
doc.as_text() # plain text of a Doc / Sheet grid / Slides deck
doc.replace_text("draft", "final") # Doc & Slides; doc.append_text / insert_text / delete_range too
doc.suggestions # Docs suggesting-mode edits (read-only)
doc.as_text(suggestions="accepted") # preview as if suggestions accepted / rejected
sheet = ws.open(sheet_url)
sheet.update("Sheet1!A1", [["=SUM(B:B)"]], value_input_option="USER_ENTERED") # formulas ok
sheet.append_rows("Sheet1!A1", [["new", "row"]]) # append after the last row
sheet.as_text(tab="Data") # one tab; as_text() renders all tabs
sheet.comments_by_cell("B11") # comments mapped back to a cell (best-effort)
Entry points: Workspace.from_credentials(creds) (bring-your-own credentials — user OAuth or a service account), Workspace(backend=…) (dependency injection / run-as-a-service), Workspace.from_oauth(...) (interactive login). Writes are on by default; pass read_only=True to lock them (and narrow to read-only OAuth scopes). Public types — Comment, Author, Reply, Location, Suggestion, Slide — are importable from the package root.
Capability boundaries
The library is document-scoped and honest about what the Google APIs can't do:
- Suggestions are read/preview only.
Doc.suggestionsreads suggesting-mode edits andas_text(suggestions="accepted"|"rejected")previews the outcome, but accepting/rejecting is impossible via the API (UnsupportedOperation) — Google exposes no endpoint. Reserved for a futurePlaywrightBackend. - No document discovery. You hand the library a file id/URL (
Workspace.open(id)); there is nofiles.list/search. A "sweep my documents" job enumerates files itself and opens each:files = drive.files().list(q="mimeType='application/vnd.google-apps.document'", fields="files(id)").execute()["files"] for f in files: doc = ws.open(f["id"]) ...
- Sheets cell-anchored comments can't be created via the API —
sheet.create_comment(text, cell=…)posts a file-level comment with a#gid=…&range=…deep-link instead.
Using it on a user's behalf (production)
This library is a building block for MCP servers / agents / automations acting on a user's behalf with a full-Drive token. Before deploying, read SECURITY.md — prompt injection through document/comment content is the primary risk. In short:
- Credential seam:
from_oauth+ localtoken.jsonis PoC/CLI scaffolding (run_local_server()can't run on a server). In production the host runs its own OAuth, stores per-user tokens in a secret store, and passes ready credentials viaWorkspace.from_credentials(creds)— the production entry point. - Concurrency: one
Workspaceper request/user; never share aWorkspace(or its backend) across threads —googleapiclientclients aren't thread-safe. The stack is synchronous; wrap calls inasyncio.to_thread(...)from async code. - Isolation & least authority: a
Workspacebinds one user's credentials — never reuse it across users. Default toread_only=Trueand escalate to a write-capableWorkspacedeliberately, per operation.
Documents
| Document | What it is |
|---|---|
docs/superpowers/specs/2026-07-20-csa-google-workspace-design.md |
The design spec. Scope, two-axis architecture, API surface, error model, phasing. |
docs/superpowers/plans/ |
The six phased, TDD implementation plans (foundations · comments · content read · cell-mapping · content write · suggestions read). |
research/google-drive-comments-reference.md |
Canonical reference on how Drive/Sheets comments actually work: the 10 API methods, fields, resolution/deletion models, OAuth scopes, and the hard truth about the anchor field. |
research/docs-suggestions-reference.md |
How Docs suggestions behave: readable (incl. accepted/rejected previews), but no accept/reject endpoint and no author exposed. |
research/server-landscape.md |
Source-verified survey of prior-art servers that handle Google comments. |
research/mcp-server-design.md · research/mcp-protocol-notes.md |
Earlier MCP-server design + protocol notes (kept for reference should an MCP wrapper be added). |
experiments/ |
Runnable empirical probes (with dated RESULTS.md): anchor-probe, comment-lifecycle, docs-suggestions, sheets-cellmap. Probe beats docs. |
CHANGELOG.md |
What changed in each refresh, and why. |
Three things worth knowing
- Comments are a Google Drive API v3 concern — not the Sheets/Docs/Slides APIs (those handle content). One comment API serves all three file types. (Sheets notes are separate and out of scope.)
- You cannot anchor a comment to a specific Sheets cell via the API. Google treats API-created anchors as unanchored; the real anchor is a
workbook-rangewith an opaque id. Mapping a comment back to a cell requires exporting the sheet as XLSX and parsing the comment XML — the central hard problem, which the library solves (best-effort) viacomment.location/sheet.comments_by_cell(). - The space isn't greenfield, so the value is in the hard parts — reliable read-side cell mapping and clean Docs/Sheets/Slides coverage — not merely "supporting comments." See
server-landscape.md.
License
Licensed under the Apache License, Version 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file csa_google_workspace-0.1.0.tar.gz.
File metadata
- Download URL: csa_google_workspace-0.1.0.tar.gz
- Upload date:
- Size: 54.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
807c2e9ca48f99b6b40aba1b7eabd2a87565fea3d0857db8dab29627c797b064
|
|
| MD5 |
59f0521358e545d188375cc09c9adc8b
|
|
| BLAKE2b-256 |
7ccb35804f96ec89ad65c30a179b1128170310a47d4f8c515ccd3ecd10962b17
|
Provenance
The following attestation bundles were made for csa_google_workspace-0.1.0.tar.gz:
Publisher:
release.yml on CloudSecurityAlliance/csa-google-workspace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csa_google_workspace-0.1.0.tar.gz -
Subject digest:
807c2e9ca48f99b6b40aba1b7eabd2a87565fea3d0857db8dab29627c797b064 - Sigstore transparency entry: 2222013079
- Sigstore integration time:
-
Permalink:
CloudSecurityAlliance/csa-google-workspace@10fc509ce14bf84603993fee39ade6c1c23c15e8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/CloudSecurityAlliance
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@10fc509ce14bf84603993fee39ade6c1c23c15e8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file csa_google_workspace-0.1.0-py3-none-any.whl.
File metadata
- Download URL: csa_google_workspace-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd69a19c47cd3b7b17f137c75b419d7a53ab6cbdbee6e68806b32624c9865d8c
|
|
| MD5 |
6825a18a8c925472a325f44cfbefa9fa
|
|
| BLAKE2b-256 |
a515186ecb9eee53f4b6dfeb2fa46750fbb87e5f903c8e31ce20baec3ff83a42
|
Provenance
The following attestation bundles were made for csa_google_workspace-0.1.0-py3-none-any.whl:
Publisher:
release.yml on CloudSecurityAlliance/csa-google-workspace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csa_google_workspace-0.1.0-py3-none-any.whl -
Subject digest:
bd69a19c47cd3b7b17f137c75b419d7a53ab6cbdbee6e68806b32624c9865d8c - Sigstore transparency entry: 2222013514
- Sigstore integration time:
-
Permalink:
CloudSecurityAlliance/csa-google-workspace@10fc509ce14bf84603993fee39ade6c1c23c15e8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/CloudSecurityAlliance
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@10fc509ce14bf84603993fee39ade6c1c23c15e8 -
Trigger Event:
release
-
Statement type: