Set up Harvey, a free tool that finds businesses, reads their sites and drafts cold emails on your Claude plan, with every send waiting for your yes.
Swipe or tap Next · checked on 2026-10-31
Open a terminal, download Harvey and start Claude Code inside its folder. Then paste the prompt below. It walks you through every step in this guide one at a time, has you paste your own keys into a file (never into the chat), runs a small free test, and stops before anything costs money or reaches a real person.
Download Harvey and start Claude in it
git clone https://github.com/ethanplusai/harvey.git
cd harvey
claudeThe setup prompt (copy all of it) · lines 1-1 of 22. Copy all copies the whole prompt; read it in full on the page.
Hi Claude. Please be my patient setup helper. I run a small business and I'm not technical: one step at a time, tell me exactly what to type or click, and wait for me after each step.Hi Claude. Please be my patient setup helper. I run a small business and I'm not technical: one step at a time, tell me exactly what to type or click, and wait for me after each step.
Goal: set up Harvey (the open-source sales tool in this folder, https://github.com/ethanplusai/harvey) so it finds businesses that fit what I sell, reads their websites, and drafts cold emails and replies on my Claude plan. Every email waits in Harvey's Outbox for my approval. We are not sending anything to anyone today.
Steps:
1. Check what's installed: python3 --version (Harvey needs Python 3.11 or newer) and claude --version. If my Python is too old, tell me how to get Python 3.13 for my computer and stop.
2. Install Harvey in this folder: make a virtual environment (a private copy of Python just for Harvey) with Python 3.11 or newer, activate it, run pip install -e . and check that harvey --help works. On a Mac use python3.13 -m venv .venv, never the plain python3 that came with the Mac.
3. Ask me what I already have: a separate domain just for cold email (never my main one), a Google Workspace mailbox on it, and whether SPF, DKIM and DMARC are set up (three DNS records that prove my mail really comes from me). For anything missing, walk me through it one record at a time. Buying a domain or a mailbox costs money, so I decide.
4. Mailbox: walk me through a Google Cloud project with the Gmail API turned on, the Google Auth platform set up with the audience Internal, and an OAuth client of type Desktop app. Then copy .env.example to .env and have me open .env and paste GMAIL_CLIENT_ID and GMAIL_CLIENT_SECRET in myself. Make sure channels.email.provider is gmail. Then I run harvey gmail auth in my own terminal (it opens a browser sign-in) and harvey gmail test.
5. Email checker: help me get a free Reoon key, and I paste it into .env as REOON_API_KEY myself. Without a checker, every address stays a guess and Harvey never sends to it.
6. Train Harvey on my website: harvey train followed by my site's address. Then go through harvey.local.yaml with me, one part at a time: persona (my real name and my sending address), product, product.offer.goal (book_call) and product.offer.booking_url (my calendar link), icp (the industries, job titles and cities I sell to), compliance.postal_address (my real mailing address), compliance.do_not_contact (my customers and competitors), channels.email.max_daily_sends (20 to start) and channels.email.require_approval (must stay true). Ask me before you change anything.
7. Signals: run harvey signals, explain the list in plain words, then run harvey signals --confirm free so it only collects what costs nothing.
8. Free test: harvey discover --estimate --city "<my city, ST>" and show me the estimate. Then harvey discover --city "<my city, ST>" --limit 20 on the free OpenStreetMap source. Then harvey warmup, and explain READY or NOT READY.
9. Tell me how to start the dashboard (harvey dashboard) and Harvey (harvey run) in two terminal windows of my own. Explain the Outbox: A approves, R rejects, E edits. Remind me not to approve anything until harvey warmup says READY.
House rules for this setup:
- If you use a technical word, explain it in plain English the first time.
- Ask me before you assume anything about my business, my accounts or my setup.
- Stop and check with me before anything that costs money: a domain, a mailbox, a warmup plan, a paid lead source.
- Stop and check with me before anything that sends, posts or publishes to real people. Never approve an email in the Outbox, never run harvey outbox --approve-all, and never turn on autopilot.
- Stop and check with me before you delete or overwrite anything, including .env and harvey.local.yaml.
- Never ask me for, print or save a password, key or token. I paste keys into .env myself, you don't read .env, and you never print the dashboard link's token.Harvey ships a CLAUDE.md file that turns Claude Code into its setup wizard (say “set up Harvey for me”). The prompt above runs on top of it and adds the stops I care about: no keys in the chat, nothing that costs money without your yes, and nothing approved in the Outbox.
This is the manual way: every step and every command. Claude follows it too.
Harvey wakes up every 15 minutes, does the most important job (replies first, then sending, writing and finding), and goes back to sleep. A reply from anyone at a company stops the sequence to everyone there.
Harvey finds companies and reads what they publish on their own websites. It's built for selling to other businesses: let's say a commercial roofer going after property managers, or a marketing shop going after contractors. It doesn't find homeowners, and you shouldn't try to make it.
Harvey doesn't put meetings on your calendar by itself yet (calendar booking is on its roadmap). It works each thread toward your calendar link, and a thread it has no safe answer for, like somebody asking for a contract, comes back to you in Conversations.
This is the part everybody wants to skip, and it's the part that decides whether anybody ever sees your email. Harvey's own docs say it plainly: sending cold email from your main domain, or at volume on day one, lands you in spam permanently.
A close cousin of your real name, never your main domain. Harvey's example is getacme.com next to acme.com. Any domain registrar works; prices vary by name.
Harvey recommends Gmail through Google Workspace for under 50 cold emails a day. Starter is $7.00 per user a month before tax on Google's pricing page (checked 2026-10-31). Microsoft 365 works too; Harvey's docs/microsoft365.md covers it.
Add a TXT record with the host @ and this value (Google's record for a domain that only sends through Google Workspace):
SPF TXT record value
v=spf1 include:_spf.google.com ~allPick your sending domain, click Generate New Record (2048-bit if your host allows it), then Generate. Copy the host name (it looks like google._domainkey) and the TXT value into a new TXT record at your domain host. Don't click Start authentication until that record is saved. Then go back and click it. Google says a brand-new mailbox may need 24 to 72 hours before it can make the key, and up to 48 hours after that to start working.
A TXT record at _dmarc (that's _dmarc.yourdomain.com). Google recommends starting with p=none, which only reports, and tightening it later.
DMARC TXT record value
v=DMARC1; p=none; rua=mailto:<a mailbox you actually read>Harvey says 2 to 4 weeks of warmup before real volume, and keep it on after. It recommends TrulyInbox: the Free plan covers one mailbox, and Harvey can read your warmup progress through TrulyInbox's API, which starts on Starter ($29 a month billed monthly, or $264 a year, checked 2026-10-31). Using another warmup service is fine; run harvey trulyinbox other later and it stops asking. Write down the day warmup started.
Check with python3 --version. Macs ship 3.9, which won't run Harvey. With Homebrew, Harvey's docs say install 3.13; without Homebrew, use the installer from python.org.
Mac with Homebrew
brew install python@3.13
python3.13 --versionSkip this if claude --version already prints a version. Claude Code needs a paid plan (Pro, Max, Team or Enterprise); the free plan doesn't include it. Run claude once and follow the browser login.
Install (Mac, Linux, WSL)
curl -fsSL https://claude.ai/install.sh | bash
# open a NEW terminal window, then:
claude --versionNote python3.13, not python3: on a Mac the plain one is the old 3.9. On Linux, plain python3 is fine if it says 3.11 or newer. You'll run source .venv/bin/activate every time you open a new terminal for Harvey.
Download, install, check
git clone https://github.com/ethanplusai/harvey.git
cd harvey
python3.13 -m venv .venv && source .venv/bin/activate && pip install -e .
harvey --helpCreate a new project and turn on the Gmail API for it. Google's “Enable Google Workspace APIs” help page shows where, if you get lost.
Give it a name (only you see it) and a support email, then under Audience pick Internal, add a contact email and finish. Internal is offered because your mailbox is on Google Workspace, and it matters: Google's docs say a project set to External while in testing gets a login that expires in 7 days.
Application type Desktop app, any name, then Create. Copy the client ID and the client secret.
.env and nowhere else.Make your own copy of the settings file, open it, and paste the values after the equals signs. Harvey's .env is already set to never be uploaded to GitHub.
Make .env and open it (Mac; on Linux use nano .env)
cp .env.example .env
open -e .envThe first command opens a Google sign-in in your browser. Sign in as the sending mailbox and allow it.
Connect Gmail
harvey gmail auth
harvey gmail testHarvey works out each company's email pattern and checks one address instead of guessing six. Without a checker key, every address stays a “guess” and Harvey never sends to it. Reoon's free plan checks 20 a day (about 600 a month) plus 100 credits at sign-up (checked 2026-10-31). Paste the key into .env as REOON_API_KEY. ZeroBounce works too, and Harvey sends Microsoft 365 and Google Workspace catch-all domains to it if you add both.
GMAIL_CLIENT_IDYour Desktop app OAuth client's ID
Google Cloud: Google Auth platform > ClientsGMAIL_CLIENT_SECRETThat client's secret
Same place, shown when you create itREOON_API_KEYThe email checker (one checker key is enough)
reoon.com, after sign-upZEROBOUNCE_API_KEYOptional second checker, good for catch-all domains
zerobounce.netTRULYINBOX_API_KEYOptional: lets harvey warmup read your warmup progress
Filled in for you by harvey trulyinbox connectHarvey reads your site and writes what it learned into harvey.local.yaml (your private settings file; it wins over the template and never goes to GitHub), plus a product knowledge file in skills/. It guesses your sender name and email from your domain, so you'll fix those next.
Train
harvey train https://your-company.comOpen harvey.local.yaml and check these, line by line. The industries and city below are an Example (made up): put in who you actually sell to. Cities need the state and the country.
require_approval: true is the line that keeps every email in the Outbox until you say yes. Leave it on.harvey.local.yaml: the parts to check · Part 1 of 2 · Copy copies all 24 lines
persona:
name: "<your real name>"
email: "<your sending address>"
product:
offer:
goal: "book_call"
booking_method: "calendar_link"
booking_url: "<your calendar link>"
meeting_duration: "15 minutes"
icp:
industries: ["Property Management", "Restaurant"] # Example (made up)
titles: ["Owner", "Property Manager"]
geography: ["Tampa, FL, United States"]
channels:
email:persona:
name: "<your real name>"
email: "<your sending address>"
product:
offer:
goal: "book_call"
booking_method: "calendar_link"
booking_url: "<your calendar link>"
meeting_duration: "15 minutes"
icp:
industries: ["Property Management", "Restaurant"] # Example (made up)
titles: ["Owner", "Property Manager"]
geography: ["Tampa, FL, United States"]
channels:
email:
provider: "gmail"
max_daily_sends: 20
require_approval: true
warmup:
start_date: "<the day your warmup started, YYYY-MM-DD>"
compliance:
postal_address: "<a mailing address you get mail at>"
do_not_contact:
- "<a customer's or competitor's domain>"harvey.local.yaml: the parts to check · Part 2 of 2 · Copy copies all 24 lines
provider: "gmail"
max_daily_sends: 20
require_approval: true
warmup:
start_date: "<the day your warmup started, YYYY-MM-DD>"
compliance:
postal_address: "<a mailing address you get mail at>"
do_not_contact:
- "<a customer's or competitor's domain>"Harvey knows how to collect 29 signals about a business and collects none of them until you say so. Look at the list, then turn on the free ones (26 of them). Paid ones like search rank need their own yes later.
Review, then confirm the free signals
harvey signals
harvey signals --confirm freeThis costs no money: the default lead source is free, reading websites is free, and the writing uses your Claude plan. With approval on, nothing goes out.
Estimate, then a small batch in one city
harvey discover --estimate --city "Tampa, FL"
harvey discover --city "Tampa, FL" --limit 20
harvey warmupThe estimate should say $0 on OpenStreetMap, and --limit 20 caps each search at 20 results. Then open two terminal windows in the Harvey folder (run source .venv/bin/activate in each). In the first, start the dashboard and open the private link it prints. In the second, start Harvey.
Window 1: the dashboard
harvey dashboardWindow 2: Harvey
harvey runGive it a few cycles, then open the Outbox. Each draft sits next to what Harvey knew when it wrote it: the company, how the address was found and checked, and the signals the email uses. Read five. Don't approve any of them yet.
Good: under 75 words, a first line about something you can confirm on their site in ten seconds, one plain ask, the opt-out line and your mailing address underneath. Bad: “I came across your company,” a fact you can't find on their site, or a pitch with a price in the first email. Reject those with R and fix the writing rules (the prompts under “Real use” below).
Stop Harvey with Ctrl+C when you're done looking.
OpenStreetMap maps storefronts, so trades without one barely show up: Harvey's docs say under 2,000 roofers and under 2,300 plumbers in the whole US. It's for trying the pipeline. For real volume, harvey discover --providers lists the paid sources with their prices, and every run estimates first with a hard cap (--max-spend, $1.00 by default).
harvey warmup checks SPF, DKIM, DMARC, the domain's age, blocklists and your warmup, and ends with READY or NOT READY. With warmup.start_date set, Harvey sends no cold email for 14 days, then starts at 5 a day and adds 3 a day up to your cap. Replies always go out.
J and K move, E edits, A approves, R rejects. Approved emails go out on schedule, under your daily cap. To send only in each recipient’s office hours, remove the # marks in front of send_window in your settings file. I'd read every one for the first couple of weeks. You're the sender, it's your name on it.
This stops all outgoing email right away and leaves everything else as it is. harvey sending resume turns it back on.
Kill switch
harvey sending pauseIn the US, the FTC says each email that breaks CAN-SPAM can cost up to $53,088.
Harvey's defaults cover a lot of it: a truthful subject, an opt-out line under every cold email that it honors right away, your mailing address in the footer, a do-not-contact list, and a truthful yes if somebody asks whether they're talking to an AI.
Read the FTC's guide for the rest, keep those defaults, and if you're sending at scale or into a regulated industry, talk to a lawyer. This isn't legal advice.
Harvey can send without your approval (Settings > Sending, where you have to type autopilot). Even then it holds any email with a link to somebody else's domain, because a website or a reply can carry planted instructions. I'd keep approving by hand until you've read enough drafts to trust them, and turning it off is one click.
Harvey's sales know-how lives in plain text files in skills/. Change a file and the next cycle writes differently, no restart. Run these in Claude Code inside the Harvey folder.
1. The drafts sound generic
Run harvey outbox and read the drafts waiting there. Tell me in plain words what makes them sound pushy or generic. Then suggest edits to skills/email_frameworks.md that fix it. Show me the change and wait for my yes before you save it. Don't approve or reject anything in the Outbox.Run harvey outbox and read the drafts waiting there. Tell me in plain words what makes them sound pushy or generic. Then suggest edits to skills/email_frameworks.md that fix it. Show me the change and wait for my yes before you save it. Don't approve or reject anything in the Outbox.2. Teach it how you answer an objection
When people say <the objection you hear most>, here's what I actually say back: <your answer>. Add that to skills/objection_handling.md in the same style as the rest of the file. Show me the change and wait for my yes.3. Keep people off the list
Add these to compliance.do_not_contact in harvey.local.yaml, one per line: <your customers' and competitors' domains>. Show me the change before you save it.4. The Monday check
Run harvey status and harvey warmup. Tell me in five lines: what went out, how many replies, any bounces, whether the domain is still READY, and what's waiting on me. Don't approve, send or change anything.Checked 2026-10-31 on each company's pricing page. Prices and intro offers change: check before you buy.
The plan's limits are the real budget. Harvey runs on your Claude plan's usage, not a per-email bill, and it throttles itself: by default it stops at 80% of your quota so there's room left for your own Claude work (usage.max_daily_claude_percent in the settings file). harvey usage shows where you are. Paid lead sources are the only thing that bills per use, and they always estimate first.
command not found: harveyRun source .venv/bin/activate in the Harvey folder first. Every new terminal window needs it.
SyntaxError or odd import errors right after install (Mac)Your virtual environment was built with the Mac's old Python 3.9. Rebuild it: rm -rf .venv && python3.13 -m venv .venv && source .venv/bin/activate && pip install -e .
ModuleNotFoundError: No module named 'harvey' (Mac)Run harvey install again; it fixes a Mac quirk that hides the package from Python 3.13.
Run claude update, and claude once to make sure you're logged in on a paid plan. harvey status --check checks it without using a prompt.
Confirm signals first (harvey signals --confirm free): nothing is collected until you do. On the free source, your trade may just be thin there; see harvey discover --providers.
No email checker key, so every address is a “guess.” Add REOON_API_KEY (or ZeroBounce) to .env.
Your sign-in screen is set to External in testing, and Google expires those logins in 7 days. Set the audience to Internal (Google Auth platform), then run harvey gmail auth again.
Open the exact link harvey dashboard printed, or print it again with harvey dashboard --url. Use 127.0.0.1 or localhost, not another name.
Almost always the domain, not the writing. Run harvey warmup, fix any missing SPF, DKIM or DMARC record, make sure warmup is still running, and halve your daily cap.
Set compliance.postal_address in harvey.local.yaml. US law wants a mailing address you actually get mail at.
Check quiet hours and whether it hit its share of your Claude plan. harvey status shows the current state.
That's OpenStreetMap's free servers. Wait a few minutes, or use a paid source for bulk work.
Ctrl+C in the window running harvey run, or harvey sending pause to stop outgoing email and leave the rest running. Everything is saved, so it picks up cleanly.
On your computer: data/harvey.db, .env and your settings files. Nothing goes anywhere except the services you connected. The dashboard only answers on your own machine.
What each page backs up is listed at the end of the full guide.
Cold email still works when it does the homework first: a real reason in the first line, a checked address, and your eyes on every email before it goes.
Want help setting this up? Receipts Group builds these systems.
Open the full guide as a page (every file in full, plus the table of contents).