Skip to content

jamiequint/groundeffect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GroundEffect

Hyper-fast, local Gmail and Google Calendar indexing for Claude Code.

GroundEffect is a local headless IMAP/CalDav client, Claude Code skill, and MCP server built in Rust with LanceDB.

Features

  • Hybrid Search: BM25 full-text + vector semantic search with Reciprocal Rank Fusion
  • Local Embeddings: Runs nomic-embed-text-v1.5 locally via Candle with Metal acceleration
  • Multi-Account: Connect unlimited Gmail/GCal accounts with independent sync
  • MCP Integration: Exposes email and calendar tools directly to Claude Code
  • Real-time Sync: IMAP IDLE for instant email notifications, CalDAV polling for calendar
  • HTML Text Extraction: Automatically converts HTML emails to clean plain text using html2text
  • Pluggable Token Storage: File-based (default) or PostgreSQL with AES-256-GCM encryption

Quick Start

1. Install

brew tap jamiequint/groundeffect
brew install groundeffect

This automatically:

  • Installs the daemon (starts at login)
  • Installs the Claude Code skill
  • Adds permissions to run groundeffect commands

2. Configure OAuth

Create a Google Cloud project with OAuth credentials:

  1. Go to Google Cloud Console
  2. Create a project and enable Gmail API and Google Calendar API
  3. Go to APIs & Services > Credentials
  4. Create OAuth client ID (Desktop app type)
  5. Add your credentials:
echo 'export GROUNDEFFECT_GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"' >> ~/.zshrc
echo 'export GROUNDEFFECT_GOOGLE_CLIENT_SECRET="your-client-secret"' >> ~/.zshrc
source ~/.zshrc

3. Add an Account

groundeffect account add

This opens a browser for Google OAuth. After authentication, the daemon syncs automatically.

That's it! Ask Claude Code to search your emails and calendar.

CLI Reference

All commands output JSON by default. Add --human for readable output.

Account Commands

Command Description
account list List all connected accounts
account show <account> Show account details and sync status
account add Add new Google account via OAuth
account reauth <account> Re-authenticate an existing account via OAuth
account delete <account> Remove account and all synced data
account configure <account> Update account settings (alias, attachments)

Parameters for add:

Parameter Description Default
--years Years of email history to sync (1-20 or "all") 1
--attachments Enable automatic attachment download off
--alias Friendly name for the account -

Email Commands

Command Description
email search <query> Hybrid BM25 + semantic search
email list List recent emails
email show <id> Show full email content
email thread <thread_id> Show all emails in a thread
email send Compose and send email
email attachment <id> Get attachment content
email folders List IMAP folders

Parameters for search:

Parameter Description Default
--account Filter to specific account all
--limit Max results (max: 100) 10
--from Filter by sender -
--to Filter by recipient -
--date-from Filter after date (YYYY-MM-DD) -
--date-to Filter before date (YYYY-MM-DD) -
--has-attachment Filter emails with attachments -

Parameters for send:

Parameter Description
--from Account to send from (required)
--to Recipient(s) (required)
--subject Email subject (required)
--body Email body (required)
--cc CC recipients
--bcc BCC recipients
--reply-to Email ID to reply to (for threading)
--html Force HTML format (auto-detected from markdown/URLs)
--save-as-draft Save as draft instead of sending
--confirm Send immediately (without: preview only)

Draft Commands

Command Description
email draft create Create a new email draft
email draft list List all drafts for an account
email draft show <id> Show full draft content
email draft update <id> Update an existing draft
email draft send <id> Send a draft
email draft delete <id> Delete a draft

Parameters for draft create:

Parameter Description
--from Account to create draft in (required)
--to Recipient(s)
--subject Email subject
--body Email body
--cc CC recipients
--bcc BCC recipients
--html Force HTML format
--reply-to Email ID to reply to (for threading)

Calendar Commands

Command Description
calendar events List events in a date range (no query required)
calendar search <query> Search events with semantic search
calendar show <id> Show event details
calendar create Create new event

Parameters for events:

Parameter Description Default
--from Start date (YYYY-MM-DD) today
--to End date (YYYY-MM-DD) 7 days from start
--account Filter to specific account(s) all
--limit Max results (max: 200) 50
--human Human-readable output grouped by date -

Use calendar events to answer questions like "what's on my calendar tomorrow" or "show me my meetings next week" without requiring a search query.

Parameters for create:

Parameter Description Default
--account Account to create event in (required) -
--summary Event title (required) -
--start Start time (ISO 8601) (required) -
--end End time (ISO 8601) (required) -
--description Event description -
--location Event location -
--attendees Attendee emails (repeatable) -
--calendar Calendar ID primary

Sync Commands

Command Description
sync status Show sync status for all accounts
sync reset --account <a> --confirm Clear all synced data
sync extend --account <a> --target-date <d> Sync older emails back to date
sync resume-from --account <a> --target-date <d> Force sync to resume from date
sync download-attachments --account <a> Download pending attachments

Daemon Commands

Command Description
daemon install Install launchd agent (auto-start at login)
daemon uninstall Remove launchd agent
daemon status Check if daemon is running
daemon restart Restart the daemon

Config Commands

Command Description
config settings View/modify daemon settings
config add-permissions Add to Claude Code allowlist
config remove-permissions Remove from Claude Code allowlist

Parameters for settings:

Parameter Description Default
--logging Enable/disable file logging off
--email-interval Email poll interval in seconds (60-3600) 300
--calendar-interval Calendar poll interval in seconds (60-3600) 300
--max-fetches Max concurrent fetches (1-50) 10
--timezone User timezone for date parsing (e.g., America/Los_Angeles) UTC
--embedding-provider Embedding backend: local, openrouter, remote local
--embedding-batch-size Embedding + IMAP fetch batch size (1-1024) 128
--openrouter-model OpenRouter embedding model ID openai/text-embedding-3-small
--openrouter-api-key-env Env var name with OpenRouter API key OPENROUTER_API_KEY

Embeddings backend examples:

# Use local embeddings (default)
groundeffect config settings --embedding-provider local

# Use OpenRouter embeddings
export OPENROUTER_API_KEY="your-key"
groundeffect config settings --embedding-provider openrouter

# Set embedding + IMAP fetch batch size (128 recommended for Gmail/OpenRouter stability)
groundeffect config settings --embedding-batch-size 128

# Optional: set a different OpenRouter model
groundeffect config settings --openrouter-model "openai/text-embedding-3-large"

MCP Integration (Alternative)

If you prefer MCP over the CLI skill, add to ~/.claude.json:

{
  "mcpServers": {
    "groundeffect": {
      "type": "stdio",
      "command": "groundeffect-mcp",
      "env": {
        "GROUNDEFFECT_GOOGLE_CLIENT_ID": "${GROUNDEFFECT_GOOGLE_CLIENT_ID}",
        "GROUNDEFFECT_GOOGLE_CLIENT_SECRET": "${GROUNDEFFECT_GOOGLE_CLIENT_SECRET}"
      }
    }
  }
}

The skill is faster (direct CLI calls vs MCP JSON-RPC overhead) but MCP works with other MCP-compatible clients.

Build from Source

git clone https://github.com/jamiequint/groundeffect.git
cd groundeffect
cargo build --release

Binaries:

  • target/release/groundeffect - CLI
  • target/release/groundeffect-daemon - Background sync daemon
  • target/release/groundeffect-mcp - MCP server

Install manually:

# Install binaries
sudo cp target/release/groundeffect* /usr/local/bin/

# Install skill
cp -r skill ~/.claude/skills/groundeffect

# Install daemon
groundeffect daemon install

# Add permissions
groundeffect config add-permissions

Data Storage

~/.config/groundeffect/
├── config.toml            # Main configuration
├── daemon.toml            # Daemon configuration
└── tokens/                # OAuth tokens (file provider)

~/.local/share/groundeffect/
├── lancedb/               # LanceDB database
├── attachments/           # Downloaded attachments
├── models/                # Embedding model files
├── logs/                  # Log files
└── cache/
    └── sync_state/        # Sync state

~/.claude/skills/groundeffect/   # Claude Code skill

Token Storage

By default, OAuth tokens are stored in ~/.config/groundeffect/tokens/ as encrypted JSON files.

For server deployments or ephemeral containers, you can store tokens in PostgreSQL instead. This requires the postgres feature.

PostgreSQL Token Storage

  1. Build with the postgres feature:

    cargo build --release --features postgres
  2. Create the tokens table:

    CREATE TABLE IF NOT EXISTS groundeffect_tokens (
        email VARCHAR(255) PRIMARY KEY,
        encrypted_tokens BYTEA NOT NULL,
        created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
    );
  3. Configure in ~/.config/groundeffect/config.toml:

    [tokens]
    provider = "postgres"
    database_url_env = "DATABASE_URL"
    encryption_key_env = "GE_TOKEN_ENCRYPTION_KEY"
    # table_name = "groundeffect_tokens"  # optional
  4. Set environment variables:

    export DATABASE_URL="postgres://user:pass@localhost/mydb"
    export GE_TOKEN_ENCRYPTION_KEY="your-secret-key-here"

Tokens are encrypted at rest using AES-256-GCM with a key derived from your encryption key via HKDF-SHA256.

Troubleshooting

"OAuth token expired"

Re-authenticate:

groundeffect account reauth <email-or-alias>

Daemon not running

Check status and restart:

groundeffect daemon status
groundeffect daemon restart

Or check launchd:

launchctl list | grep groundeffect

View logs

tail -f ~/.local/share/groundeffect/logs/daemon.log

Enable logging if disabled:

groundeffect config settings --logging true
groundeffect daemon restart

High memory usage

Embedding model uses ~500MB-1GB during active embedding. Normal when idle.

Architecture

┌──────────────┐      ┌──────────────────┐
│ Claude Code  │─────►│ groundeffect-mcp │────────┐
│ (MCP Host)   │stdio │                  │        │
└──────────────┘      └──────────────────┘        │
                                                  ▼
┌──────────────┐      ┌──────────────────┐    ┌─────────┐
│ Claude Code  │─────►│ groundeffect     │───►│ LanceDB │
│ (Skill/Bash) │      │ (CLI)            │    └─────────┘
└──────────────┘      └──────────────────┘         ▲
                                                   │
                      ┌──────────────────┐         │
                      │ groundeffect-    │─────────┘
                      │ daemon           │◄──── IMAP/CalDAV
                      └──────────────────┘

License

MIT

About

Hyper-fast, local Gmail and Google Calendar indexing for Claude Code.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors