DEV Community

Cover image for I Built a Relationship Intelligence CRM with Claude Code + Coral — Here's the Route
Geetansh Vikram
Geetansh Vikram

Posted on

I Built a Relationship Intelligence CRM with Claude Code + Coral — Here's the Route

Live demo: coral-hackaton.onrender.com

Repo: github.com/Geetansh-12/coral_hackaton

Most people don't lose touch with contacts because they don't care — they lose touch because relationship data is scattered across Gmail, Slack, LinkedIn, calendar invites, and community servers. I built Coral CRM for the Pirates of the Coral-bean hackathon to show what happens when you stop treating those surfaces as separate apps and start treating them as one SQL graph powered by Coral.

This post is the reproducible route: problem → architecture → Coral capabilities → live demo → custom Discord source spec.


The problem

Relationship intelligence breaks when every channel owns a slice of context:

  • Gmail knows what you said
  • Calendar knows when you meet
  • Slack knows what happened in DMs
  • LinkedIn knows job changes
  • Discord knows community engagement

An AI agent can't recommend "reach out to Sarah before Thursday's meeting" if it only sees one inbox. You need a unified graph the agent can query safely.


Why Coral (not just MCP connectors)

MCP connectors are great for tool calls. Coral adds something different: SQL over APIs.

Instead of writing bespoke fetch logic for every source, Coral exposes tables you can JOIN:

SELECT c.name, c.company, c.health_score,
       g.public_repos, g.followers
FROM contacts c
JOIN github.users g ON c.github_username = g.username
WHERE c.health_score < 50;
Enter fullscreen mode Exit fullscreen mode

That query runs in the SQL Explorer of Coral CRM and returns live GitHub profile data joined against local contacts — proof that federated joins aren't vaporware.

Coral also gives you:

  • Catalog discoverycoral.tables, coral.columns, coral.inputs
  • Cache/freshness observabilitycoral.query_log
  • One auth/retry/pagination layer for agent workloads

Architecture in 60 seconds

Landing / Dashboard / Explorer / AI Chat
              ↓
        Next.js API routes (/api/query, /api/chat, /api/brief)
              ↓
     Demo Mode (mock)  OR  Live Mode (SQLite + coral CLI)
              ↓
   contact_relationship_graph  ← 6 seeded sources + live GitHub/Discord
Enter fullscreen mode Exit fullscreen mode

Demo Mode works with zero API keys — judges can click through immediately.

Live Mode seeds SQLite locally and spawns the real coral binary for federated queries.

Tech stack: Next.js 14, TypeScript, Tailwind, Gemini (free tier) for AI, better-sqlite3, Coral CLI.


Step-by-step: run it yourself

git clone https://github.com/Geetansh-12/coral_hackaton.git
cd coral_hackaton
npm install
npm run seed   # optional — seeds SQLite for live mode
npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000. The app starts in Demo Mode with 34 realistic contacts.

Switch to Live Mode

Copy .env.local.example.env.local:

DEMO_MODE=false
GEMINI_API_KEY=your_key
GITHUB_TOKEN=ghp_...
DISCORD_BOT_TOKEN=your_bot_token   # for the custom Discord source
Enter fullscreen mode Exit fullscreen mode

Install the Discord source spec:

coral source lint ./sources/discord/manifest.yaml
coral source add --file ./sources/discord/manifest.yaml --interactive
coral source test discord
Enter fullscreen mode Exit fullscreen mode

Coral capabilities we demonstrate (7/7)

1. SQL interface over multiple sources

Six seeded tables in sql/schema.sql: Gmail threads, Calendar events, Slack messages, LinkedIn activity, Twitter activity, Notion contacts.

2. Cross-source JOINs

The contact_relationship_graph materialized view LEFT JOINs all six on email and computes a health_score.

3. Catalog discovery

SELECT schema, table, sql_reference, source_type, freshness
FROM coral.tables ORDER BY schema;
Enter fullscreen mode Exit fullscreen mode

4. Parameter hints

SELECT query, parameter, name, type, required FROM coral.inputs;
Enter fullscreen mode Exit fullscreen mode

5. Cache & freshness

SELECT query_name, sources_joined, cache_hit_rate, avg_ms
FROM coral.query_log;
Enter fullscreen mode Exit fullscreen mode

6. Real CLI execution

In Live Mode, /api/query spawns coral sql --format json asynchronously — no blocking the Next.js event loop on slow API calls.

7. Pluggable source architecture

Settings page shows connector diagnostics per source. We added a custom Discord source spec (see below).


The judge demo flow

  1. Open /dashboard → click Judge Demo
  2. Show Agent Plan and Coral Capability Cockpit
  3. Open SQL Explorer → run the cross-source GitHub JOIN recipe
  4. Open a contact → generate a pre-meeting brief → export it
  5. Ask the chat agent: "What Coral capabilities does this demo use?"

Screenshots are in docs/screenshots/ in the repo.


Building a custom Discord source spec (bounty track)

Coral ships Gmail, GitHub, Slack, etc. — but Discord wasn't in the catalog. For the hackathon "Chart New Waters" track, I wrote a YAML source spec that maps Discord REST API v10 endpoints to SQL tables.

File: sources/discord/manifest.yaml

Tables exposed:

SQL table Discord API
discord.current_user GET /users/@me
discord.guilds GET /users/@me/guilds
discord.channels GET /guilds/{guild_id}/channels
discord.messages GET /channels/{channel_id}/messages
discord.members GET /guilds/{guild_id}/members

Auth pattern:

auth:
  type: HeaderAuth
  headers:
    - name: Authorization
      from: template
      template: Bot {{input.DISCORD_BOT_TOKEN}}
Enter fullscreen mode Exit fullscreen mode

Nested JSON → SQL columns using Coral's __ convention:

- name: author__username
  expr:
    kind: path
    path: [author, username]
Enter fullscreen mode Exit fullscreen mode

Validation workflow:

coral source lint ./sources/discord/manifest.yaml
coral source add --file ./sources/discord/manifest.yaml
coral source test discord
Enter fullscreen mode Exit fullscreen mode

Example CRM query once installed:

SELECT author__username, content, timestamp
FROM discord.messages
WHERE channel_id = 'YOUR_CHANNEL_ID'
ORDER BY timestamp DESC
LIMIT 20;
Enter fullscreen mode Exit fullscreen mode

Full docs: sources/discord/README.md

Upstream PR target: withcoral/coralsources/community/discord/


What I learned

  1. Start with one table. Guilds first, then channels, then messages. Run coral source test after each addition.
  2. Nested fields need explicit expr. Don't assume author__username auto-flattens — declare the path.
  3. Filters in URL paths use {{filter.guild_id}} — same pattern as other community specs (OSV, dbt Cloud).
  4. Demo + Live dual mode was the right call for hackathon judges — zero friction to explore, real CLI when credentials exist.
  5. Docker on Render beats serverless for a 150MB Coral binary — one container, authentic live URL.

What's next

  • Open upstream PR for the Discord source spec
  • Join Discord messages into contact_relationship_graph on username/nickname
  • OAuth device flow for Gmail/Calendar in production

Links


Top comments (0)