The CRM I run my practice on.
I took 2nth.ai's contacts out of HubSpot and into a CRM I own: Postgres in South Africa, a Cloudflare Worker in front, and my mailbox, calendar and invoices joined up. Penny, an AI agent, keeps it current. She organises freely, and asks before anything leaves the business.
The CRM only knew what I typed into it.
Contacts lived in HubSpot. The real relationships lived in my inbox and calendar, and what clients owe lived in my invoicing system. Contracts lived in my head. A SaaS CRM charges per seat to hold that data somewhere else. An AI assistant can't help with what it can't see.
So I built the CRM I tell clients to own. One Postgres database holds every source, and an agent works on top of it with tools that have clear limits.
Sources in, an agent on top, a person in charge.
Everything flows in
- Website enquiries, with POPIA consent recorded as given.
- Microsoft 365 mail and calendar, read-only, every 15 minutes.
- Invoices and payments from my invoicing app, every hour.
- The HubSpot history, imported once.
One record
- Contacts, companies, deals, contracts and tasks.
- Every email, meeting, note and change on one timeline.
- Matched by email domain and name, with no manual tagging.
The agent works it
- Reads mail, meetings, invoices and the pipeline.
- Adds contacts, updates deals, sets next steps and tasks.
- Every change is logged on the timeline as hers.
I decide
- A morning brief by email: today's meetings, who's waiting, what needs attention.
- Anything that would leave the business waits in an outbox for my approval.
- Chat with Penny from any record.
Things a CRM should notice by itself.
Who's waiting, who went quiet
Threads where the other side wrote last. Contacts who emailed often and then stopped. Steady two-way email with no deal yet, offered as a deal suggestion.
Deals with context
Each deal card shows the next meeting or when we last met. It opens to every field, notes, tasks, recent email and the timeline.
Checked against invoices
Retainers, projects and licences matched to what was actually invoiced. Flags like "Not invoiced for October yet", overdue amounts, and "Ends in 30 days".
Meetings, linked
Meetings with other people are linked to their contacts, companies and deals. Personal and private entries are never stored.
People from email
Everyone I've written to who isn't in the CRM, ready to add in one click with their past email and meetings attached. Or Bcc a tagged address and everyone on the email is added and tagged.
Filled in from signatures
Job title, phone, LinkedIn and company read from the signature in each person's own email. Empty fields are filled; anything that differs is offered, never overwritten.
Primary and key contacts
Each company has one primary contact and a short list of key contacts, with everyone else folded away. Penny writes to the people who matter first.
Forms without HubSpot
Enquiry forms on four websites post straight into the CRM, checked by Cloudflare Turnstile and a rate limit, with an email alert that links to the new contact.
POPIA by design
Opt-in only comes from the person, never from me or the agent. Imported contacts start as "unknown". Bulk export is deliberately left out.
An agent with limits you can read.
Penny works through 24 tools. Twelve can change data, and none can send an email; a draft goes to the outbox for me to approve. She is model-agnostic: calls go through Cloudflare AI Gateway, and an eval harness scores candidate models on the same CRM tasks before I switch.
"What meetings do I have tomorrow?" Penny checks the calendar, names who's attending, links the meeting to its deal, and points out an attendee who isn't in the CRM yet.
Illustrative. Real briefs name real clients, so they stay private.
Data in South Africa, on systems I own.
The database sits on a Google Cloud VM in the South Africa region, reached through a Cloudflare Tunnel. Nothing on it is open to the internet. The app is a Cloudflare Worker with its own passkey sign-in (Face ID or Touch ID, with an emailed code as the fallback), and it installs on a phone home screen. Mailbox sign-in tokens are encrypted at rest, and the mailbox and calendar connection is read-only.
- Database: PostgreSQL on Google Cloud (africa-south1), reached through Hyperdrive
- App: Cloudflare Workers (Hono), queues for the agent's longer jobs, cron for syncs
- Sign-in: passkeys, with a one-time emailed code as the fallback. Only the website form endpoint is public
- Mail and calendar: Microsoft Graph, delegated read-only access
- Agent: any model through Cloudflare AI Gateway, with evals before each switch
The same build, on the systems you already use.
The CRM core stays the same: Postgres, a Worker, Penny. Each connector in the diagram can be swapped for the one your business runs.
| Layer | As built | Also connects to |
|---|---|---|
| Mail and calendar | Microsoft 365 (Graph, read-only) | Google Workspace: Gmail and Google Calendar APIs, read-only, with push updates instead of polling |
| Team sign-in | Passkeys, emailed code | Microsoft Entra ID or Google sign-in for teams, with roles per person |
| Accounting | My invoicing app | Xero, Sage Business Cloud, QuickBooks, ERPNext |
| Database | PostgreSQL on Google Cloud, South Africa | Azure Database for PostgreSQL (South Africa North), Amazon RDS (Cape Town), or your own server |
| Messaging | Email alerts (Resend) | WhatsApp Business, Microsoft Teams or Slack alerts; WhatsApp threads on the timeline |
| Newsletters | listmonk, opt-in only | Mailchimp or Brevo, synced with consent kept in the CRM |
| AI models | Open models on Workers AI | Claude, GPT or Gemini through the same gateway; Azure OpenAI for Microsoft-only shops |
| Reporting | Views in the app | Power BI, Looker Studio or Metabase, straight on Postgres |
| Coming from | HubSpot, imported once | Salesforce, Pipedrive, Zoho or spreadsheets: contacts, companies, deals and form history |
Own your CRM, and let an agent work it.
A walkthrough of this build takes 30 minutes. A stack audit then maps your sources (Microsoft 365 or Google Workspace, accounting, ERP, support desk) and what moving off HubSpot would take. Keep the data where your compliance needs it, pick the model, and keep a person on every send.