Skip to main content
Glama
README.md
# Callsheet

**Walk into every first call prepared. Leave with the follow-up written, scheduled and logged.**

Callsheet is a Claude skill plus a small server. Before a call it writes a one-page account brief from public sources: news, what's happening across their industry, and who you're meeting. After the call it turns your notes into a follow-up email, a CRM note and a task, and can send the email at a time you choose. Every touch lands in an activity log and your Google Sheet. **Nothing is written or sent until you've seen the exact content and approved it.**

> Personal project. **Not affiliated with Anthropic or HubSpot.** Talk to your Legal and IT teams before using any AI tool on real customer work.

**New here? Start with the tutorial.** A 16-minute click-through (10 short lessons): `uv run callsheet tutorial`, or open [`docs/tutorial/index.html`](docs/tutorial/index.html).

---

## What you get

| Before the call | After the call | Between calls |
|---|---|---|
| **Three lines for the car:** why now, what to lead with, the first question to ask | A **follow-up email** under 120 words, in the buyer's own words | **"Where are we with Acme?"** A timeline of emails, calls and promises, with what's overdue |
| **Who you're meeting:** their role, what they've said publicly for work, what they'll likely care about | A **CRM note** and **one task** for HubSpot | **Reply drafts** to the prospect's latest email |
| **In the news** (last 90 days), summarised and linked | **Send it now or later**: the exact email you approved, at the time you picked | **Follow-up series** that stop the moment they reply |
| **Industry watch:** what happened at their peers and how it may affect them | **Book the next meeting** on your calendar | **Activity log and time sheet**: who, what, when, how long, how, in Google Sheets |
| Company channels, priorities from job posts, fit, questions, objections | Everything held until you say **"approve"** | **Voice:** "Hey Siri, Callsheet", then "prep me for my 2pm" |
| **Directions:** "navigate to my 2pm" opens Maps to the meeting or the company's office | **Recording to notes:** transcribed on your Mac, then synthesized into call notes | **Reviewer agent:** "make this better" checks sources and tightens any draft |
| **Plan my day:** meetings ordered to save driving, with leave-by times and fuel cost | **Receipts by camera:** snap it, confirm, done; photo filed with the expense | **Group by area:** "save gas this week" suggests which meetings share a day |
| **HubSpot and/or Salesforce:** deal context in the brief; notes, tasks and activity written after approval | **Send to Concur, Expensify or any expense system:** preview, approve, never twice | **Any expense, any wording:** 26 categories, refunds, foreign currency, card statement import | **Expense report** per currency and category, with flags for missing receipts and purposes |

Examples on made-up data: [brief](examples/sample-brief-northwind.md) · [follow-up and scheduling](examples/sample-follow-up-northwind.md) · [correspondence](examples/sample-correspondence-northwind.md)

## Why reps use it

- **One page instead of ten tabs.** Filings, job boards, news, industry moves and the company's own channels, all linked.
- **Nothing to fact-check blind.** Every line has a source, or it's flagged for you to verify.
- **Follow-up done in a minute**, and sent when it'll be read, not at 11pm.
- **No more "did I log that?"** Calls, emails and minutes go to your sheet as you work.
- **Safe by design.** You approve every write. Scheduled emails are fingerprinted, capped at 3 recipients, and held if the prospect replies.

## Four things you do: Prep, Follow up, Plan, Expense

| | Say | You get |
|---|---|---|
| **Prep** | "what's my day?" | Every meeting with its three lines, leave-by time, emails needing you, expenses to finish. Can arrive at 7 am (`scripts/install_digest.sh`) |
| | "prep meridian" | The three lines in about a second (no AI call), then the full cited brief |
| | "practice this call" | Claude plays the buyer from the brief and your objections, then scores you |
| **Follow up** | paste your notes | One card: email, CRM note, task, logged call. **Approve all** once |
| **Plan** | "plan my day" | Meetings ordered to save driving, with leave-by times |
| **Expense** | "parking $18", "send my expenses to Concur" | Logged in plain words; sent after you approve the preview |

## Things to say

```
Prep me for my 2pm
Prep me for a first call with Northwind
Follow up on my call with Northwind. Here are my notes: ...
approve, send Tuesday 9am, and set up follow-ups
Where are we with Northwind?
Log a 30-minute call with Dana Reyes, VP Engineering at Northwind, about the pilot
What's my time sheet this week?
```

Sloppy works too: `prep acme`, `acme call tmrw`, `follow up acme`.

## Demo worlds: seven fictional sales teams

For demos and training, Callsheet ships seven fictional worlds, one per industry. Each has a seller, a rep, accounts, a month of calls and emails, expenses, routes, an outbox in every state, a pipeline, and its own set of test cases.

| Industry | Seller → main prospect (all fictional) | Shows off |
|---|---|---|
| Technology: SaaS, Enterprise Software & Cybersecurity | Lumora → Northwind Logistics | planted job-post instruction caught; priorities from postings; flexible drop-in |
| Medical Devices & Healthcare Sales | Corvia Medical → Meridian Health Partners | private hospital with no SEC data; HIPAA answered from the profile; 7 am in-service |
| Financial Services & Fintech | Ledgerline → Fourth Street Bancorp | two companies with the same name; email-exfiltration attempt flagged; Salesforce |
| Commercial & Residential Real Estate | Parcelwise → Granite Peak Properties REIT | five property tours reordered; three-day regrouping; "Apartments"/"Residences" allowed |
| Insurance: Life, Commercial & P/C | Clearwater Risk → Globex Insurance | no job board; cyber-incident trigger; HIPAA gap; stale fact; follow-ups held on reply |
| Manufacturing | Forgepoint → Tailwind Industrial | late meeting flagged; drop-in that can't fit; statement import; 900+ miles |
| Hospitality (international) | Tablesetter → Wingtip Hospitality | euro and dollar totals kept apart; duplicate taxi; time-zone-aware send |

```sh
uv sync --extra sheets
uv run callsheet demo-data --sheets          # all seven under ~/.callsheet-demo, plus Excel workbooks
source ~/.callsheet-demo/corvia/env          # point Callsheet at one world
uv run callsheet expenses                    # …then any command, or "prep meridian" in Claude
```

Each world's workbook has README, Accounts, Pipeline, Activity, Time Sheet, Expenses, Expense Summary, Mileage, Outbox, Route Plan, Reimbursement and Test Cases tabs, with live formulas. A combined workbook compares all seven. Try it hands-on in the **live demo** [`docs/demo/interactive.html`](docs/demo/interactive.html): pick an industry, type or tap requests, approve writes, and watch the outbox, expenses and tool calls update, or press **Start the 2-minute tour**. The walkthrough page is [`docs/demo/index.html`](docs/demo/index.html); rebuild both from the app's own output with `uv run python scripts/build_demo_page.py`. Demo data never touches your real `~/.callsheet`.

## See it work in one minute (no accounts needed)

```sh
uv run callsheet demo
```

Runs the research tools on recorded, made-up data and explains each step: finding the company, filings, job posts (including a planted instruction it catches), industry watch, company channels and the contact's professional record.

---

## Install (no terminal): Claude Desktop extension

1. **Get two files** from your enablement team (or build them with `uv run --with pillow python scripts/build_extension.py`):
   `Callsheet.mcpb` and `Callsheet-skill.zip`.
2. **Double-click `Callsheet.mcpb`.** Claude Desktop opens an install screen; click **Install**. Claude Desktop downloads Python and everything Callsheet needs by itself.
3. **Fill in the settings** it shows. Only "Your name and email" matters to start; the rest (Google Maps, Salesforce, Concur, Sheets…) are optional, and keys are stored securely. For a demo, type an industry in **Demo world** (e.g. `corvia`) and leave the rest blank.
4. **Add the skill:** Customize → Skills → Upload → `Callsheet-skill.zip`.
5. **Connect** HubSpot, Gmail and Google Calendar in Settings → Connectors (set HubSpot writes to Ask).

Then say "what's my day?" or "prep meridian". The extension also adds three prompts to Claude's menu: What's my day, Prep, and Follow-up.

The terminal setup below is for developers and for the add-ons that run on a schedule (background sender, morning digest, voice).

## Set up (developers)

You need [uv](https://docs.astral.sh/uv/), and Claude Desktop or Claude Code.

**Core, about 15 minutes**

1. **Check your setup.** This prints a checklist and the exact config to paste into Claude Desktop:
   ```sh
   export CALLSHEET_SEC_USER_AGENT="Your Name you@example.com"   # the SEC asks tools to identify themselves
   uv run callsheet check --online
   ```
2. **Connect the server.** In Claude Desktop: Settings → Developer → Edit Config, then paste the block `check` printed. In Claude Code, `.mcp.json` connects it when you open this folder.
3. **Install the skill:** `./scripts/install_skill.sh`. This installs it for Claude Code and builds `dist/callsheet-skill.zip`; upload the ZIP in Claude Desktop under Customize → Skills.
4. **Connect HubSpot, Gmail and Google Calendar** in Claude (Settings → Connectors). Set HubSpot's write tools and Calendar's create-event tool to **Ask**.
5. **Check your seller profile.** `profiles/claude.yaml` ships **unchecked**. Open each source, confirm the line, then add `checked: YYYY-MM-DD`.

**Optional add-ons**

| Add-on | Setup | Guide |
|---|---|---|
| Scheduled sending | `./scripts/install_sender.sh`. Checks the outbox every 15 minutes while your Mac is awake. Needs Claude Code signed in with your Claude account, for the Gmail connector | [How sending works](#how-scheduled-sending-stays-safe) |
| Google Sheets log | Paste one Apps Script into your sheet, then set two env vars | [`integrations/google-sheets/Code.gs`](integrations/google-sheets/Code.gs) |
| Voice / Siri, directions, voice choice | A 3-action Shortcut named "Callsheet" | [`integrations/voice/README.md`](integrations/voice/README.md) |
| Call recordings → notes | `uv sync --extra transcribe` (local Whisper) | [Call recordings to notes](integrations/voice/README.md#call-recordings-to-notes) |
| Live gas prices, road distances | Google Maps key with Places API (New), Routes API, Geocoding API → `CALLSHEET_GOOGLE_MAPS_KEY`. Also set `CALLSHEET_BASE_ADDRESS`, `CALLSHEET_MPG` | [Route planning](#route-planning-and-gas) |
| Receipts, mileage, expenses | iPhone "Callsheet Receipt" Shortcut; set `CALLSHEET_MILEAGE_RATE` | [`integrations/receipts/README.md`](integrations/receipts/README.md) |
| Salesforce (with or instead of HubSpot) | `CALLSHEET_CRM=both` (or `salesforce`); your Salesforce admin creates a connected app | [`integrations/salesforce/README.md`](integrations/salesforce/README.md) |
| Concur, Expensify, Ramp, Brex, Navan… | `callsheet reimburse`; Concur needs your Concur admin's approved app | [`integrations/reimbursement/README.md`](integrations/reimbursement/README.md) |
| Connect other tools | `uv run callsheet api` (REST + OpenAPI), `CALLSHEET_WEBHOOKS`, `callsheet serve --http` (MCP) | [`docs/api/README.md`](docs/api/README.md) |

Settings can live in `~/.callsheet/env` (sourced by the voice and sender scripts).

## How it works

```text
You (typing, or "Hey Siri, Callsheet")
  → Claude, following the callsheet skill
      ← Google Calendar: which company and contact is the 2pm with?
      ↔ Callsheet server
           research (read-only, public):  SEC company list · 8-K filings · job boards ·
                                          industry peers' filings · company channels ·
                                          the contact's mentions in company filings
           outbox (local, approved only): schedule · confirm · cancel · hold
           activity log (local + your Sheet)
      ← Claude web search: news, industry news, public work statements
  → You see the brief / follow-up → "approve" → Claude confirms each write
      → HubSpot: note + task      → Gmail: draft, or the outbox for a set time
      → Calendar: meeting or reminder

Every 15 min: background sender → due approved emails → reply check → send exactly → log
```

## Route planning and gas

```sh
uv run callsheet route --stop "Northwind|1 Northwind Way, Evanston IL" \
  --stop "Contoso|500 Lake St, Oak Park IL|2026-11-10T14:00:00-06:00|60" --stop "Fabrikam|Naperville IL"
uv run callsheet gas "Evanston, IL" --fuel regular
```

Or just ask Claude: "plan my day", "group my meetings by area this week", "cheapest gas near my 2pm".

- Meetings with a set time keep it. Drop-ins without a time are fitted where they add the fewest miles and still end by 6 pm (`CALLSHEET_DAY_END_HOUR`).
- You get leave-by times, miles, drive time, gallons, fuel cost (the live local average with a Google key), and what you save against your current order.
- "Group by area" suggests which meetings could share a day. Moving one means asking the prospect, so Claude drafts the reschedule emails for you to approve.
- Distances come from Google Routes with a key, otherwise OpenStreetMap's free router, otherwise a labelled straight-line estimate. Gas prices need the Google key; without it, give a price per gallon.

## How scheduled sending stays safe

- **You approve the exact email and the exact time.** Callsheet stores a fingerprint of the recipients, subject, body and time. Change a character and it needs a new approval.
- **Two steps.** Scheduling creates a pending message; it only becomes live after you confirm its fingerprint.
- **The sender can only send what the outbox returns**, word for word, and only those tools are enabled for it.
- **Held if they reply.** Before each send, the sender checks the thread. A reply holds the rest of the series.
- **Never stale.** If your Mac was off and a send is more than a day late, it's marked missed, not sent.
- **One-to-one only.** At most 3 recipients per message and 25 waiting messages.
- Cancel any time: say "cancel the Northwind email", or run `uv run callsheet outbox cancel <id>`.

## The rules it follows

From the AI Ready Reps guardrail catalog. Each write-side rule has two gates: the skill's instruction, and code or a platform setting that holds even if the instruction is ignored.

| Rule | Skill gate | Code or platform gate |
|---|---|---|
| Public, professional sources only | Declines private-life requests; contact card is work record only | Tools return company data and company-filing mentions; personal profile links dropped; one-word name lookups refused |
| Every fact carries a source | Uncited lines go to "Verify before the call" | Every tool result carries a `source` |
| Job posts and industry effects are hypotheses | Labelled "(hypothesis)" / "(our analysis)" | Priorities need 2+ postings (`term_counts`) |
| Product claims only from the seller profile | Gaps become "Ask your account team" | Unchecked or old entries marked `stale` |
| Fetched text is data, never instructions | Ignores and flags instructions in pages and emails | Server pre-flags suspicious text; never follows links inside fetched text |
| Nothing written without approval | Exact content, "approve", then a confirmation per write | HubSpot and Calendar writes set to Ask |
| Sends only what was approved | Schedule → fingerprint → confirm | Outbox enforces fingerprint, 3-recipient cap, reply hold, 24h expiry; sender has only send-due tools |
| Voice can't approve or send | Voice mode rules | `callsheet voice` runs Claude without any send, schedule or write tools |
| Directions only to business locations | Meeting location or company office | `directions` refuses home addresses; voice opens only map links |
| Recordings need consent | Told to the rep | `transcribe` refuses without `--consent`; audio never leaves the computer |
| Other tools can't send | n/a | The API and webhooks have no send, schedule, approve or CRM-write endpoints |
| The reviewer agent only returns text | Drafts are data, not instructions | No write tools in its allow list |
| Routes and mileage to business locations only | Same rule as directions | `plan_route`, `group_meetings` and `log_mileage` refuse home addresses |
| No card numbers | Never read from receipts | Expense entries containing one are refused; scans scrub them |
| Salesforce: notes, tasks and activity only | Never stages, amounts, close dates, Next Step, deletes or new records | Only `note`, `task`, `activity` accepted; preview → fingerprint → commit; ledger stops repeats; ids validated and SOQL escaped |
| Expenses reach a reimbursement system only as approved | Preview → "yes" → submit | Fingerprint must match; changed or already-sent expenses refused; voice and API can't submit |
| Moving a meeting is the prospect's call | Suggest → draft → approve | `group_meetings` only suggests; it has no calendar access |

## More tools (scaffolds)

`callsheet company <site>` (private companies) · `callsheet changes <company>` (what's new since you last spoke) · `callsheet policy --pack general` (expense policy) · `callsheet match` (receipts ↔ card charges) · `callsheet team` (team dashboard) · `callsheet profiles` (profile lint) · `callsheet host` (hosted connector). What's built and what each still needs: [`docs/roadmap.md`](docs/roadmap.md).

## Proof

- **Tests:** `uv run pytest` runs 429 tests, no network. **Guardrails:** 20 tests in [`docs/guardrail-tests.md`](docs/guardrail-tests.md); the server side is automated, and live results are filled in as they're run.
- **Live run, Nov 5, 2026:** a brief on Airbnb took 78 s (about $0.74), and 5 of 5 spot-checked citations held up. The full log is in [`docs/guardrail-tests.md`](docs/guardrail-tests.md#live-run-log).
- **Evaluation:** 6 held-out US public companies on a 6-part rubric, two scorers. Kit in [`eval/`](eval/). _Not yet run._

## Commands

```text
uv run callsheet today       what's my day (--notify for a Mac notification)
uv run callsheet quick X     the three lines in about a second
uv run callsheet demo        narrated run on made-up data
uv run callsheet check       setup checklist (--online also tests the SEC)
uv run callsheet tutorial    open the rep tutorial
uv run callsheet log         activity log and time sheet   (log sync | log csv)
uv run callsheet outbox      scheduled emails              (outbox cancel <id>)
uv run callsheet voice "…"   ask by voice or text          (--speak reads it aloud, --open opens Maps)
uv run callsheet navigate    directions                    (--company NWND, --mode transit, --app google)
uv run callsheet transcribe  recording → transcript        (--consent required, --synthesize for notes)
uv run callsheet speak       read text or a brief aloud    (--voice, --rate, --list-voices)
uv run callsheet improve     reviewer agent on any draft   (--kind brief|follow-up|transcript)
uv run callsheet route       order the day to save gas     (--stop "Name|address|time|minutes")
uv run callsheet gas "…"     live gas prices nearby        (--fuel diesel, --radius 3)
uv run callsheet mileage A B log business miles            (--purpose, --round-trip)
uv run callsheet expense     log any expense               (uber $23.45, hotel 180 --currency EUR, flight 189 --refund)
uv run callsheet receipt     read a receipt photo, confirm, log
uv run callsheet receipts inbox   process the iPhone Shortcut's photos
uv run callsheet expenses    report, or update / delete / import a statement   (--since, --csv)
uv run callsheet crm         Salesforce/HubSpot status, find, context, events, sync-activity
uv run callsheet reimburse   send expenses to Concur, Expensify, a webhook or CSV   (status | prepare | submit)
uv run callsheet demo-data   7 fictional demo worlds       (--sheets for Excel workbooks)
uv run callsheet api         REST API + OpenAPI            (--show-key, --spec)
uv run callsheet serve --http   MCP over HTTP for other AI apps
uv run pytest                all tests
```

## Project layout

```text
src/callsheet/          server + CLI: sec, greenhouse, industry, presence, profiles, outbox, activity,
                        navigation, speech, review, api, events, geo, fuel, planner, expenses, reimburse,
                        salesforce
skill/callsheet/        the skill, with brief, contact-card, follow-up and correspondence templates
skill/agents/           callsheet-reviewer subagent (also the rules for `callsheet improve`)
profiles/               seller profiles (claude.yaml, acme-fictional.yaml)
integrations/           google-sheets (Apps Script), voice (Siri Shortcut), receipts (camera Shortcut),
                        reimbursement (Concur, Expensify, webhook, CSV), salesforce
config/                 reimburse.example.yaml (category → expense type mapping)
scripts/                install_skill, install_sender, send_due, voice
tests/                  pytest suite + synthetic fixtures (fictional companies)
examples/               sample brief, follow-up, correspondence, mock call notes
docs/                   tutorial, quick start, guardrail tests, api (guide + openapi.json)
eval/                   held-out evaluation kit
```

## Make your own seller profile

Copy `profiles/acme-fictional.yaml`. List up to 3 products with the job-post words that signal fit, and 5 objections with one-sentence answers. Every entry needs a `source` URL and a `checked` date. Run `uv run pytest` to validate it, then say "use the <name> profile".

## License

MIT. See [LICENSE](LICENSE).