ppl is a personal CRM designed to be used by AI agents on behalf of their human. Your human's relationships, notes, journal, tasks, and reminders live here. You read from it before acting, and you write to it after acting.
Are you the human? Pick your AI below, paste your token, copy the config. Done.
Step 1: Get your token. Open the MCP setup wizard (logged in) to generate one, or create a scoped key under Settings > API.
Step 2: Paste it here (stays in your browser, never sent anywhere):
Step 3: Pick your AI and copy the config:
Claude Desktop / Claude Code: paste this into your MCP config (claude_desktop_config.json, or run claude mcp add):
{
"mcpServers": {
"ppl": {
"url": "https://ppl.gift/mcp",
"headers": { "Authorization": "Bearer YOUR_PPL_TOKEN" }
}
}
}
You initiate the connection. Your human approves once in their browser. No signup forms for you to fill, no API keys to copy and paste.
POST https://ppl.gift/api/agent/connect/request
Content-Type: application/json
{
"client_name": "Claude",
"redirect_uri": "https://your-app.example/connected"
}
The response gives you an approve_url and a poll_url:
{
"data": {
"id": 42,
"connect_code": "abc123...",
"approve_url": "https://ppl.gift/c/abc123...",
"poll_url": "https://ppl.gift/api/agent/connect/42/status",
"expires_at": "2026-10-01T14:50:00+00:00",
"instructions": "Show the approve_url to your human..."
}
}
approve_url to your human. They open it, sign up or log in if needed, and click Approve. The request expires after 15 minutes.poll_url until the status is approved:
{
"data": {
"id": 42,
"status": "approved",
"api_token": "ppl_live_...",
"base_url": "https://ppl.gift",
"mcp_url": "https://ppl.gift/mcp"
}
}
The token is revealed exactly once. Save it immediately. Later polls return approved without the token.
If the human denies, the status becomes denied. If the 15 minutes pass, it becomes expired; just start a new request.
Connect to our hosted MCP endpoint. Nothing to install, nothing to self-host.
POST https://ppl.gift/mcp
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}
It speaks JSON-RPC 2.0 over Streamable HTTP and exposes 55 tools, grouped here:
get_briefing, get_next_action, ask_memory, semantic_search, get_person_digest, get_suggested_actions, describe_schemalist_contacts, get_contact, create_contact, update_contact, delete_contact, merge_contacts, unmerge_contacts, check_duplicates, find_contact_duplicates, get_contact_timelinecreate_note, list_notes, get_note, update_note, delete_notecreate_task, list_tasks, get_task, update_task, complete_task, delete_taskcreate_reminder, list_reminders, get_reminder, update_reminder, delete_remindercreate_call, list_calls, get_call, update_call, delete_callcreate_gift, list_gifts, get_gift, update_gift, delete_giftcreate_journal_entry, list_journal_entries, get_journal_entry, update_journal_entry, delete_journal_entrylog_interactionget_voice_profile, get_profile_cardupdate_location, get_nearby_contacts, get_whisper_briefing, im_withMachine-readable spec: /.well-known/ppl.json
Use ppl like this:
get_next_action or get_briefing to see who needs attention.get_person_digest or ask_memory so you answer from real data, not guesses.log_interaction with who, what, and when. The response tells you if the relationship status changed.relationship.status_changed webhook to get pushed when someone drifts.Human? Want your AI to do this automatically without being asked? Read the Memory Sync Guide: it has a copy-paste system prompt snippet for Claude, Grok, ChatGPT, and Cursor that makes your AI check ppl before every people-related task.
After connecting, don't ask your human to enter contacts. Run the onboarding pipeline instead. It scans their Gmail, creates contacts for new correspondents, enriches them, and generates a "who needs attention" briefing. The human does nothing.
POST /api/agent/onboard/start
# => { "data": { "id": 1, "status": "discovering", "progress": 0 } }
GET /api/agent/onboard/1/status
# => { "data": { "status": "analyzing", "progress": 65,
# "stats": { "contacts_found": 47, "contacts_created": 32,
# "contacts_enriched": 28, "insights_ready": 5 } } }
GET /api/agent/onboard/1/briefing
# => { "data": {
# "headline": "I've mapped 47 people from your email, 3 need your attention.",
# "message": "I went through your recent email and added 32 new people
# to your contacts. You didn't have to enter anything. Here's who
# needs you most: Haven't talked to Sarah in 90 days, and her
# birthday is Friday. Send a birthday message.",
# "needs_attention": [
# { "name": "Sarah Chen",
# "reason": "Haven't talked to Sarah in 90 days, and her birthday is Friday.",
# "suggested_action": "Send a birthday message" }
# ],
# "recently_active": [ ... ],
# "stats": { "total_contacts": 47, ... } } }
If Google isn't connected yet, start returns {"status": "needs_google"} and the briefing explains how to connect it. The agent should guide the human to Settings, then retry.
Present the briefing's headline and message to your human. That's the moment ppl clicks: their CRM filled itself.
ppl pushes to your agent without being asked. Two channels:
agent.briefing): every morning, ppl POSTs the full briefing payload (birthdays, reconnect candidates, overdue tasks, reminders) to the Agent webhook URL in Settings > Digest. Set it to your agent's inbound endpoint.POST /api/webhooks with {"url": "https://your-agent.example.com/ppl-events", "events": [...]}. Available events:
contact.birthday_tomorrow - someone's birthday is tomorrowcontact.gone_cold - no interaction in 45+ days (weekly)reminder.due - a reminder is due todaytask.overdue - a task is overdue (weekly)relationship.status_changed - a relationship status changedEvery event payload includes a suggested_nudge: a human-readable message your agent can forward directly. Example:
{
"event": "contact.birthday_tomorrow",
"contact_id": 687400,
"name": "Sarah Chen",
"birthday": "2026-10-02",
"suggested_nudge": "Heads up: Sarah Chen's birthday is tomorrow. Want me to draft a message?"
}
The pattern: receive webhook, surface the suggested_nudge to your human, offer to act. That's the proactive agent experience.
Prefer raw HTTP? All requests use Authorization: Bearer YOUR_API_KEY against https://ppl.gift/api. Key endpoints:
| Endpoint | What it does |
|---|---|
GET /api/agent/briefing | Morning briefing: birthdays, reconnects, overdue tasks |
GET /api/agent/next-action | The single highest-leverage action right now, with a drafted message |
POST /api/agent/ask | Ask a natural language question about your human's people |
GET /api/search/semantic?q= | Semantic search over contacts, notes, and journal |
GET /api/contacts/{id}/digest | Everything known about one person, one call |
GET /api/agent/actions | Suggested actions feed |
POST /api/interactions/log | Log that an interaction happened; returns relationship impact |
GET /api/agent/inbox | Claimable work queue for background agents |
Tokens minted through the connect flow carry these scopes: agent:briefing, agent:actions, agent:search, read:contacts, write:contacts, read:journal, write:journal, read:tasks, write:tasks. Your human can revoke access anytime from Settings > API.
Free during beta (1,000 contacts). Pro at $8/month planned for unlimited contacts and agent features.
ppl has no mobile app. On iPhone, the Shortcuts pack talks straight to this API, and your human can run all of it through Siri.
If you cannot use the connect flow (for example, a headless environment with no human in the loop), your human can create a scoped API key manually under Settings > API and paste it to you. The in-app MCP setup wizard also generates configs for running your own MCP client against the API.
Self-hosting via Docker is available for developers who want to run their own instance, but agents should use the hosted service at ppl.gift: it is always on, always updated, and backed up.