Architecture
Built-in CRM
goClaw's SQLite-backed CRM — contacts, threads, notes, and tags unified across every channel.
goClaw includes a fully-featured CRM built into the platform. No external CRM integration required. The agent reads and writes CRM data directly through MCP tools, keeping every interaction in sync.
Data model
Contacts
A contact is the core CRM entity. Every person the agent interacts with has a contact record.
interface Contact {
id: string;
email: string | null;
phone: string | null;
telegram_id: string | null;
whatsapp_number: string | null;
name: string;
company: string | null;
title: string | null;
tags: string[];
custom_fields: Record<string, string>;
created_at: number; // Unix timestamp
updated_at: number;
last_contacted_at: number | null;
group_id: string; // Permission group scope
}
Contacts are deduplicated by email address. When the agent encounters the same person across channels, they're merged into a single contact record.
Threads
A thread is a conversation with a contact on a specific channel. Each inbound message and each agent response belongs to a thread.
interface Thread {
id: string;
contact_id: string;
channel: "email" | "sms" | "telegram" | "whatsapp";
subject: string | null; // Email subject line, if applicable
status: "active" | "waiting" | "resolved" | "archived";
messages: Message[];
created_at: number;
updated_at: number;
}
Messages
interface Message {
id: string;
thread_id: string;
direction: "inbound" | "outbound";
body: string;
sender: string; // Contact ID or "agent"
channel_message_id: string | null; // External message ID
sent_at: number;
metadata: Record<string, string>;
}
Notes
Notes are agent-generated observations attached to a contact record. The agent files notes automatically after significant events.
interface Note {
id: string;
contact_id: string;
body: string;
source: "agent" | "human";
created_at: number;
tags: string[];
}
CRM MCP tools
The agent accesses the CRM through these MCP tools:
crm_search
Search contacts by name, email, company, or tags.
// Input
{ query: string; limit?: number; group_id?: string; }
// Output
Contact[]
crm_get_contact
Retrieve a full contact record including recent threads and notes.
// Input
{ contact_id: string; include_threads?: boolean; thread_limit?: number; }
// Output
Contact & { threads: Thread[]; notes: Note[] }
crm_create_contact
Create a new contact record.
// Input
{
email?: string;
phone?: string;
name: string;
company?: string;
title?: string;
tags?: string[];
}
crm_add_note
Attach a note to a contact.
// Input
{ contact_id: string; body: string; tags?: string[]; }
crm_schedule_followup
Schedule a follow-up task for a contact.
// Input
{
contact_id: string;
channel: "email" | "sms" | "telegram" | "whatsapp";
delay_days: number;
context: string; // What the follow-up is about
message_template?: string; // Optional draft message
}
Admin dashboard — Contacts view
The admin dashboard provides a full CRM interface at /contacts:
- Contact list — search, filter by tag, sort by last contacted
- Contact detail — full thread history, notes, scheduled tasks
- Manual contact creation — add contacts outside of agent activity
- Bulk import — CSV import from Apollo, Clay, LinkedIn exports
- Tags — add/remove tags for segmentation
Cross-channel identity resolution
When the same person contacts the agent from multiple channels (email on Monday, SMS on Thursday), goClaw resolves their identity to a single contact:
- Email match — exact email match across all contact records
- Phone match — normalized E.164 phone number match
- Name + company heuristic — fuzzy match when other identifiers are missing (creates a candidate, agent confirms)
If deduplication can't resolve with high confidence, the agent creates a new contact and flags it for review in the admin dashboard.
Data retention
- Active contacts: retained indefinitely
- Thread messages: retained for 24 months by default
- Notes: retained indefinitely
- Archived contacts: retained for 90 days, then soft-deleted
On tenant deactivation (subscription cancelled), all data is retained for 90 days before permanent deletion. Export available via admin dashboard or @clawrm/cli before deletion.
