#1101·gogcli

feat(contacts): use the People API batch endpoints — batchCreateContacts / batchUpdateContacts / batchDeleteContacts / batchGet

Author: sebsnykCreated Sep 9, 2026Updated Sep 9, 2026
Labelsissue-rating: 🌊 off-meta tidepoolclawsweeper:no-new-fix-prclawsweeper:needs-maintainer-reviewclawsweeper:needs-product-decisionP2impact:ux-friction

The gap

The People API ships purpose-built batch mutation endpoints:

  • people:batchCreateContacts — up to 200 contacts per request
  • people:batchUpdateContacts — up to 200 contacts per request
  • people:batchDeleteContacts — a list of resource names per request
  • people:batchGet — up to 200 resource names per request

gog contacts reaches none of them. create, update and delete each take one contact and issue one call, and get takes one resourceName.

Where it shows

gog contacts dedupe is the command that makes this concrete. Deduplicating a real address book means deleting tens or hundreds of contacts, and today that is one people.deleteContact per contact. A 300-duplicate cleanup is 300 sequential calls, each independently failable, with a partial-completion state that is hard to reason about and no single call the user can inspect before it runs.

The same shape applies to an import: bringing in a CSV of 200 contacts is 200 calls where the API offers one.

gog contacts export plus get has the mirror problem on the read side. Resolving 200 contacts one at a time is 200 calls where batchGet takes 200 resource names.

What a caller has to do today

Loop, rate-limit by hand, and write its own resume logic after a partial failure.

Proposed surface

Unlike Slides, Sheets and Forms, this is not the accumulate-then-submit gog batch pattern. The People API takes a list of contacts in one call rather than a list of heterogeneous request objects, so variadic arguments and a file input fit better and keep gog batch scoped to batchUpdate-shaped services:

gog contacts delete <resourceName> ...            # batchDeleteContacts, chunked at the API cap
gog contacts get <resourceName> ...               # batchGet
gog contacts create --from-json=<file>            # batchCreateContacts, list of contacts
gog contacts update --from-json=<file>            # batchUpdateContacts, keyed by resourceName
gog contacts dedupe                               # internally uses batchDeleteContacts

Making delete and get variadic matches how gmail archive, gmail trash and gmail mark-read already accept [<messageId> ...], so the CLI grammar is already established in the repo. Chunking at the documented per-request cap, with a stderr note per chunk, keeps a large cleanup to a handful of calls.

dedupe should route through the batch delete whether or not the user-facing flags change, since that is where the count is highest and the user has already confirmed the action.