Open source and self-hosted
The open-source AI SDR you host yourself
Self-hosted sales automation under the AGPL-3.0: one app, one PostgreSQL database, your own AI key. Email, LinkedIn and WhatsApp outreach with an AI CRM, and no one else holding your data.
$git clone https://github.com/Kandid-ai/AgentSDR.git && cd AgentSDR
$cp .env.example .env
# set BETTER_AUTH_SECRET, INTEGRATION_CREDENTIALS_KEY, POSTGRES_PASSWORD…
$docker compose up -d
services db · setup · app · cron
✓ http://localhost:3000 — sign up, create your organization
The license
AGPL-3.0: use it, change it, host it
The code is public and so are the terms. This is the short version from the README; the LICENSE file is the binding text.
You may
Use, copy, modify, self-host and distribute AgentSDR, including for commercial purposes and as a hosted service.
If you modify it
And let others use your version over a network, such as a hosted service, you must make your modified source available to those users under the same license.
Always
Keep the license and copyright notices. The container image carries the AGPL-3.0-only license label.
Read the LICENSE, how decisions are made in GOVERNANCE.md and the responsible use guide before you send anything.
Get running
Two commands from a clone to a login screen
Docker Compose is the shortest path. The same commands are in the repository's docs/self-hosting.md.
Self-hosting
One app, one database, no queue server
cron sidecar calls the scheduled endpoints.- PostgreSQL 16 or newer; Compose starts 18 for you
- Docker with Compose, or Bun 1.2+ to run from source
- Run a single app instance: the email sender has no distributed lock
- Sign up first, then connect services inside the app
$ git clone https://github.com/Kandid-ai/AgentSDR.git$ cd AgentSDR$ cp .env.example .env # set the secrets and POSTGRES_PASSWORD$ docker compose up -dStarts db (PostgreSQL 18), setup (creates the schema on an empty database), app on port 3000, and cron.
Your data, your keys
Nothing leaves except through accounts you own
Every service is connected per organization, with your own credentials. There are no shared API keys and no environment fallback.
Your server
One AgentSDR app process that you run, on the host you choose.
Your PostgreSQL
Leads, conversations, campaigns, settings. Saved credentials sit encrypted with AES-256-GCM.
Your Cloudflare R2 bucket
Call recordings, reached only through short-lived presigned links.
OpenRouter, on your keys
Every AI call goes to the one provider you picked. Fallbacks are off, so a failure fails.
Your Google Workspace and Unipile
Mailboxes, LinkedIn and WhatsApp accounts you connect, per organization.
Bring your own AI key
OpenRouter, on your keys, for classification, drafts, AI columns and call transcripts.Provider pinned
Requests go to the one provider of the model you chose, fallbacks off. A failure fails; it never reroutes.Encrypted at rest
Saved credentials are encrypted with AES-256-GCM before they reach the database.Per-organization isolation
Every query is scoped to an organization, and isolation is tested end to end.
What you connect
Five services, all from Settings
Env keeps only what is needed before the database can be read: the database URL, auth secrets, the credentials key, public URLs and cron secrets.
| Service | What it powers | Where you connect it |
|---|---|---|
| Google Workspace | Mailboxes for email sequences | Settings, Email |
| Unipile | LinkedIn and WhatsApp accounts | Settings, LinkedIn and WhatsApp |
| OpenRouter | Your model key, for every AI step | Settings, AI provider |
| Cloudflare R2 | Storage for call recordings | Settings, WhatsApp |
| Enrichment providers | Apollo and others, connected per table | Tables |
The codebase
A TypeScript codebase, laid out by area
One repository holds the app, the sending engine, the schema, the docs and the Chrome extension. Everything is TypeScript.
- Next.js 16
- React 19
- TypeScript
- PostgreSQL
- Drizzle
- Better Auth
- Tailwind 4
- Bun
- Docker
- minimum PostgreSQL major version
- 16+
- Docker Compose services: db, setup, app, cron
- 4
- queue servers or separate workers to run
- 0
- per seat, per contact or per mailbox
- $0
Contributing
Built in the open, merged on a green check
Anyone can report a bug, suggest a feature, fix an issue or improve the docs. The rules for changing the code are written down.
Open a pull request
Fork, branch from main, run the checks CI runs, and open a PR. One issue per pull request, kept small.
How decisions are made
Day-to-day changes need one maintainer approval and a green CI check. Architecture, data model and licensing changes need two maintainers.
Report a problem
Bugs go in issues. Security problems are reported privately through GitHub, never in a public issue.
# the checks CI runs before a merge$ bun run typecheck$ bun run lint$ bun run test$ bun run buildFAQ
Questions, answered
What license is AgentSDR under?
The GNU Affero General Public License v3.0 (AGPL-3.0-only). You may use, copy, modify, self-host and distribute it, including commercially and as a hosted service. If you modify it and let others use your version over a network, you must make your modified source available to those users under the same license. The LICENSE file in the repository is the binding text.
What do I need to self-host AgentSDR?
PostgreSQL 16 or newer and either Docker with Compose or Bun 1.2+ (Node.js 20.9+ also works) to run from source. The repository's docker-compose.yml starts PostgreSQL 18, a one-shot schema setup, the app and a cron sidecar. You also want a public HTTPS origin for webhooks and a Resend account for sign-in and invitation email in production.
Where is my data stored?
In your PostgreSQL database, which holds leads, conversations, settings and your encrypted integration credentials, and in your own Cloudflare R2 bucket for call recordings. AgentSDR has no shared cloud behind it, and every service you connect uses your own accounts.
How does the AI work without a shared key?
Every AI feature runs through OpenRouter on your organization's own keys. You choose the providers and models allowed, and AgentSDR pins each request to the model's provider with fallbacks off and refuses to send until you confirm shared capacity is off. If that provider fails, the request fails instead of moving elsewhere.
How are my credentials protected?
Credentials for Unipile, Google Workspace, Cloudflare R2, OpenRouter and enrichment providers are connected from Settings, not from environment variables, and stored encrypted with AES-256-GCM using INTEGRATION_CREDENTIALS_KEY. Keep a copy of that key outside the database: without it the stored credentials cannot be decrypted.
Can I run more than one instance?
Run the app as a single instance. The outreach sender loop has no distributed lock, so two instances would each send. The enrichment and CRM workers are safe to overlap, but the email scheduler is not.
How do I upgrade and contribute?
To upgrade, back up the database, pull the new version, run any new migration scripts listed in the release notes and rebuild. To contribute, read CONTRIBUTING.md: pull requests need a green CI check and one maintainer approval, and changes to architecture or the data model are discussed in an issue first.
Keep exploring
- AI CRMEvery reply classified and the lead moved for you
- FoundersFounder-led outbound without an SDR team
- AgenciesOne deployment, a separate organization per client
- Sales teamsShared pipeline, per-rep accounts, one inbox
- All comparisonsHow AgentSDR stacks up against the tools it replaces
- GuidesPlaybooks for safe, multichannel outbound
Read it, run it, change it
Clone the repository, start it with Docker Compose and connect your own accounts. The code, the data and the keys stay with you.