@marcfargas/go-easy
v0.4.0
Published
Google APIs made easy — Gmail, Drive, Calendar for AI agents and humans
Maintainers
Readme
go-easy 🟢
Google APIs made easy — Gmail, Drive & Calendar. For AI agents and humans.
Thin TypeScript wrappers over Google's individual @googleapis/* packages with:
- Own auth — unified OAuth2 with combined tokens, agent-compatible two-phase flow
- Agent-friendly types — structured
GmailMessage,DriveFile,CalendarEvent - Safety guards — destructive operations (send, share, delete) require explicit confirmation
- JSON gateways — CLI tools that always output structured JSON
- File-based body — email bodies read from files, not CLI args (no shell escaping issues)
Installation
# As a library
npm install @marcfargas/go-easy
# As CLI tools (no install needed)
npx go-gmail [email protected] search "is:unread"
npx go-drive [email protected] ls
npx go-calendar [email protected] events primaryRequires Node.js ≥ 20.
Auth Setup
go-easy manages its own OAuth2 tokens in ~/.go-easy/.
Prerequisites
- Create a project in Google Cloud Console
- Enable the Gmail, Drive, and Calendar APIs
- Create OAuth2 credentials (Desktop application type)
- Save credentials to
~/.go-easy/credentials.json:
{
"clientId": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"clientSecret": "YOUR_CLIENT_SECRET"
}Add an account
npx go-easy auth add [email protected]
# → { "status": "started", "authUrl": "https://accounts.google.com/..." }
# Open the URL, authorize, then poll:
npx go-easy auth add [email protected]
# → { "status": "complete", "email": "[email protected]", "scopes": ["gmail", "drive", "calendar"] }One combined token covers Gmail + Drive + Calendar. The flow is agent-compatible — two separate CLI calls (start + poll), no streaming stdout needed.
Manage accounts
npx go-easy auth list # List configured accounts
npx go-easy auth add [email protected] # Add or upgrade account
npx go-easy auth remove [email protected] --confirm # Remove accountQuick Start
import { getAuth } from '@marcfargas/go-easy/auth';
import { search, send } from '@marcfargas/go-easy/gmail';
import { setSafetyContext } from '@marcfargas/go-easy';
const auth = await getAuth('gmail', '[email protected]');
// Search (READ — no safety gate)
const results = await search(auth, { query: 'is:unread from:client' });
console.log(results.items);
// Send (DESTRUCTIVE — requires safety context)
setSafetyContext({
confirm: async (op) => {
console.log(`⚠️ ${op.description}`);
return true; // or prompt the user
},
});
await send(auth, {
to: '[email protected]',
subject: 'Invoice attached',
markdown: '# Invoice\n\nPlease find attached.',
attachments: ['./invoice.pdf'],
});Gateway CLIs
All gateway CLIs output JSON to stdout and work via npx:
# Gmail
npx go-gmail [email protected] search "is:unread" --max=10
npx go-gmail [email protected] get <messageId>
npx go-gmail [email protected] reply <messageId> --body-text-file=reply.txt --confirm
npx go-gmail [email protected] send [email protected] --subject="Hi" --body-text-file=body.txt --confirm
# Drive
npx go-drive [email protected] ls
npx go-drive [email protected] search "quarterly report"
npx go-drive [email protected] upload ./file.pdf --folder=<folderId>
# Calendar
npx go-calendar [email protected] events primary --from=2026-02-01T00:00:00Z
npx go-calendar [email protected] create primary --summary="Meeting" --start=... --end=...
npx go-calendar [email protected] freebusy primary --from=... --to=...Body content is always read from files (--body-text-file, --body-html-file, --body-md-file), never passed inline.
Destructive operations require --confirm. Without it, they show what would happen and exit with code 2.
Services
| Service | Module | Gateway | Status |
|---------|--------|---------|--------|
| Gmail | @marcfargas/go-easy/gmail | npx go-gmail | ✅ Ready |
| Drive | @marcfargas/go-easy/drive | npx go-drive | ✅ Ready |
| Calendar | @marcfargas/go-easy/calendar | npx go-calendar | ✅ Ready |
Gmail
| Function | Safety | Description |
|---|---|---|
| search | READ | Search messages by Gmail query |
| getMessage | READ | Get a single message with parsed fields |
| getThread | READ | Get a full conversation thread |
| listLabels | READ | List all labels |
| getAttachmentContent | READ | Download an attachment as Buffer |
| getProfile | READ | Get the authenticated email address |
| createDraft | WRITE | Create a draft (no send) |
| listDrafts | READ | List existing drafts |
| batchModifyLabels | WRITE | Add/remove labels on multiple messages |
| markdownToHtml | — | Convert Markdown to email-safe HTML |
| send | ⚠️ DESTRUCTIVE | Send a new email (supports markdown option) |
| reply | ⚠️ DESTRUCTIVE | Reply / reply-all to a message |
| forward | WRITE / ⚠️ DESTRUCTIVE | Forward as draft (default) or send (sendNow). Attachment filtering. |
| sendDraft | ⚠️ DESTRUCTIVE | Send an existing draft |
Drive
| Function | Safety | Description |
|---|---|---|
| listFiles | READ | List folder contents or query by metadata |
| searchFiles | READ | Full-text search inside file contents |
| getFile | READ | Get file metadata by ID |
| downloadFile | READ | Download binary files as Buffer |
| exportFile | READ | Export Workspace files (Docs → pdf/docx, Sheets → xlsx/csv, etc.) |
| listPermissions | READ | List sharing permissions on a file |
| uploadFile | WRITE | Upload a local file |
| createFolder | WRITE | Create a folder |
| moveFile | WRITE | Move a file to a different folder |
| renameFile | WRITE | Rename a file |
| copyFile | WRITE | Copy a file |
| trashFile | ⚠️ DESTRUCTIVE | Trash a file |
| shareFile | ⚠️ DESTRUCTIVE* | Share a file (*public sharing only; user/group is WRITE) |
| unshareFile | ⚠️ DESTRUCTIVE | Remove a sharing permission |
Calendar
| Function | Safety | Description |
|---|---|---|
| listCalendars | READ | List all calendars for the account |
| listEvents | READ | List events with time range, search, pagination |
| getEvent | READ | Get a single event by ID |
| queryFreeBusy | READ | Check availability across calendars |
| createEvent | WRITE | Create an event (with attendees, all-day, location, OOO, focus time) |
| updateEvent | WRITE | Update an existing event (full replace) |
| deleteEvent | ⚠️ DESTRUCTIVE | Delete an event (warns about attendee cancellation) |
Safety Model
Operations are classified into three levels:
| Level | Gate | Examples | |-------|------|----------| | READ | None | search, getMessage, listLabels | | WRITE | Logged | createDraft, batchModifyLabels, upload | | DESTRUCTIVE | Blocked unless confirmed | send, reply, forward, share, delete |
Set up a SafetyContext at startup to handle confirmation prompts.
Without one, all destructive operations are blocked by default.
Module Structure
go-easy uses subpath exports — import only what you need:
import { getAuth } from '@marcfargas/go-easy/auth';
import { search, send } from '@marcfargas/go-easy/gmail';
import { listFiles, uploadFile } from '@marcfargas/go-easy/drive';
import { listEvents, createEvent } from '@marcfargas/go-easy/calendar';
import { setSafetyContext } from '@marcfargas/go-easy';| Import path | What's in it |
|---|---|
| @marcfargas/go-easy | Safety context, errors, plus gmail/drive/calendar as namespaces |
| @marcfargas/go-easy/auth | getAuth, listAccounts, listAllAccounts, clearAuthCache |
| @marcfargas/go-easy/auth-store | readAccountStore, writeAccountStore, findAccount, etc. |
| @marcfargas/go-easy/scopes | SCOPES, ALL_SCOPES, scopeToService |
| @marcfargas/go-easy/gmail | All Gmail operations |
| @marcfargas/go-easy/drive | All Drive operations |
| @marcfargas/go-easy/calendar | All Calendar operations |
Development
npm install # install deps
npm run build # compile TypeScript
npm test # run tests (vitest)
npm run lint # type-check without emitting
npm run dev # watch modeLicense
MIT
