@bobfrankston/gcards
v0.1.21
Published
Google Contacts cleanup and management tool
Downloads
2,019
Maintainers
Readme
gcards - Google Contacts Management Tool
A CLI tool for syncing, managing, and cleaning up Google Contacts.
Installation
npm install -g @bobfrankston/gcardsQuick Start
# First time - specify your Gmail username
gcards sync --user yourname
# Subsequent runs remember the user
gcards sync
gcards pushCommands
gcards
Main sync and push operations (Google API):
gcards sync [-u user] [-a] # Download contacts from Google
gcards push [-u user] [-a] # Push local changes to Google
gcards -a # Process all usersgfix
One-time cleanup operations (local files only):
gfix inspect -u user # Preview all standard fixes (no changes)
gfix apply -u user # Apply all standard fixes
gfix names -u user # Preview name parsing + dup phone/email removal
gfix names -u user --apply # Parse names, remove dup phones/emails, move email/phone-only to _delete/
gfix problems -u user # Process edited problems.txt (x=delete, or replace name)
gfix birthday -u user # Preview birthday extraction
gfix birthday -u user --apply # Extract to CSV and remove
gfix undup -u user # Find duplicate contacts -> merger.json
gfix merge -u user # Merge duplicates locally (then use gcards push)
gfix export -u source -to target "pattern" # Export contacts to another userGoogle People API Fields
Identity (Names)
| Field | Read/Write | Description |
|-------|------------|-------------|
| names[].givenName | Write | First name |
| names[].familyName | Write | Last name |
| names[].middleName | Write | Middle name |
| names[].honorificPrefix | Write | Prefix (Dr., Prof., etc.) |
| names[].honorificSuffix | Write | Suffix (Jr., III, PhD, etc.) |
| names[].displayName | Read-only | Full name (Google generates from above) |
| names[].displayNameLastFirst | Read-only | Sorting form "Last, First" (Google generates) |
| names[].unstructuredName | Write | Free-form name when structured fields not available |
Sorting
| Field | Read/Write | Description |
|-------|------------|-------------|
| fileAses[].value | Write | Custom sort override (e.g., "Home Depot" instead of "The Home Depot") |
If blank, Google sorts by familyName automatically.
Contact Information
| Field | Read/Write | Description |
|-------|------------|-------------|
| emailAddresses[].value | Write | Email address |
| emailAddresses[].type | Write | Label: home, work, other |
| phoneNumbers[].value | Write | Phone number |
| phoneNumbers[].type | Write | Label: mobile, work, home, main |
Business
| Field | Read/Write | Description |
|-------|------------|-------------|
| organizations[].name | Write | Company name |
| organizations[].title | Write | Job title |
Dates
| Field | Read/Write | Description |
|-------|------------|-------------|
| birthdays[].date.year | Write | Birth year (optional) |
| birthdays[].date.month | Write | Birth month (1-12) |
| birthdays[].date.day | Write | Birth day (1-31) |
Management (Required for Updates)
| Field | Read/Write | Description |
|-------|------------|-------------|
| resourceName | Read-only | Unique contact ID (e.g., people/c12345) |
| etag | Read-only | Version key - must match when updating |
The etag prevents conflicts: if Google's version changed since you downloaded, your update will fail. Run gcards sync to get the latest version.
Data Directory
- Windows:
%APPDATA%\gcards\(app directory) - Linux/Mac:
~/.config/gcards/(app directory) - Development:
./data/symlink to app directory'sdata/folder
Directory Structure
gcards/ # App directory (%APPDATA%\gcards or ~/.config/gcards)
config.json # Last user, settings
data/ # User data directory
<username>/
contacts/ # Active contacts (*.json)
deleted/ # Backup of deleted contact files
_delete/ # User requests to delete (move files here)
_add/ # User requests to add new contacts
fix-logs/ # Logs from gfix operations
index.json # Active contact index (hasPhoto, starred flags)
deleted.json # Deleted contacts index
notdeleted.json # Contacts skipped due to photo/starred
token.json # OAuth token (read-only)
token-write.json # OAuth token (read-write)
changes.log # Log from gfix names
birthdays.csv # Extracted birthdays
merger.json # Duplicates to merge (from gfix undup)
merged.json # Processed merges (history)Fixes Applied by gfix inspect/apply
- Remove leading/trailing dashes, quotes, spaces from name fields
- Extract repeated honorific prefixes (Dr., Prof.) to
honorificPrefix - Remove duplicate phone numbers (normalized comparison)
- Remove duplicate email addresses (case-insensitive)
Name Parsing (gfix names)
When a contact has a full name in givenName but no familyName:
- Parses "First Middle Last" into separate fields
- Handles suffixes like Ph.D., M.D., P.E., Jr., III
- Updates
displayNameLastFirstto proper "Last, First" format - Cleans up
fileAsesentries (strips junk characters) - Fixes repeated words (e.g., "John Smith Smith Smith" → "John Smith")
- Creates
changes.logwith all modifications
Contacts with no real name are moved to _delete/:
- Email-only (no name field)
- Phone-only (phone number as name)
- Empty contacts (no name, email, or phone)
Recovery lists saved to emailonly.json and phoneonly.json.
Handling Problem Contacts (gfix problems)
After gfix names, ambiguous contacts are saved to problems.txt. Edit this file to fix:
- Add
xat start of line to mark for deletion - Replace the name with corrected "First Last" format
- Leave unchanged to skip
Then run gfix problems -u user to apply.
Workflow
- Initial sync:
gcards sync -u yourname - Review fixes:
gfix inspect -u yourname - Apply fixes:
gfix apply -u yourname - Parse names:
gfix names -u yourname --apply - Push to Google:
gcards push -u yourname
Deleting Contacts
Three ways to mark contacts for deletion:
- In index.json: Add
"_delete": trueto an entry - In contact JSON: Add
"_delete": trueto the contact file - Move to _delete/: Move the contact file to the
_delete/folder
Then run gcards push to apply deletions.
Photo/Starred Protection
Contacts with photos or starred status are not deleted from Google to prevent data loss:
- Contacts with non-default photos:
_deleteset to"photo" - Starred/favorite contacts:
_deleteset to"starred"
These remain in Google and index.json with the skip reason. Review notdeleted.json after push.
Backup
All deleted contact files are moved to deleted/ folder as backup (not permanently deleted).
Index entries move to deleted.json.
Duplicate Contact Merging
- Find duplicates:
gfix undup -u yourname- Creates
merger.jsonwith contacts having same name + overlapping email
- Creates
- Review: Edit
merger.json:- Remove entries you don't want to merge
- Add
"_delete": trueto delete all contacts in a group instead of merging
- Merge locally:
gfix merge -u yourname- Updates target contact files with merged data
- Marks source contacts with
_delete: true - Moves processed entries to
merged.json
- Push to Google:
gcards push -u yourname - Resync:
gcards sync -u yourname --full
Example merger.json:
[
{ "name": "John Smith", "emails": ["[email protected]"], "resourceNames": ["people/c1", "people/c2"] },
{ "name": "Spam Contact", "emails": ["[email protected]"], "resourceNames": ["people/c3", "people/c4"], "_delete": true }
]ESC Key
Press ESC during sync/push to stop safely after the current operation.
Multiple Users
# Process specific user
gcards sync -u alice
# Process all users
gcards sync -a
gcards push -aExporting Contacts Between Users
Transfer contacts from one user's account to another:
gfix export -u bob -to alice "John*" # Export contacts matching "John*"
gfix export -u bob -to ali "*@example.com" # Export by email (partial user match)
gfix export -u bob -to alice c1234567890 # Export specific contact by IDFeatures:
-usource user (partial match supported)-totarget user (partial match - "ali" matches "alice" if unique)- Pattern supports
*(any chars) and?(single char) wildcards - Matches on: displayName, givenName, familyName, "Last, First", email
- Searches both
contacts/anddeleted/directories - Multiple matches prompt for selection: number(s),
*for all,qto quit - Creates cleaned file in target's
_add/asx<sourceId>.json
After export, run gcards push -u <target> to upload.
Setup
Google API Setup
- Create Google Cloud project
- Enable People API
- Create OAuth2 credentials (Desktop app type)
- Download
credentials.jsonto the gcards directory
AI Error Explanations (Optional)
When API errors occur, gcards can use AI to explain what went wrong and suggest fixes.
Create
keys.envin your gcards app directory:- Windows:
%APPDATA%\gcards\keys.env - Linux/Mac:
~/.config/gcards/keys.env
- Windows:
Add your API key(s):
ANTHROPIC_API_KEY=sk-ant-api03-...or
OPENAI_API_KEY=sk-...
Get API keys:
- Anthropic: https://console.anthropic.com/settings/keys
- OpenAI: https://platform.openai.com/api-keys
The tool tries Anthropic first, then falls back to OpenAI if available.
License
MIT
