Contact Goat - Printing Press CLI
Prerequisites: Install the CLI
This skill drives the
binary.
You must verify the CLI is installed before invoking any command from this skill. If it is missing, install it first:
- Install via the Printing Press installer:
bash
npx -y @mvanhorn/printing-press install contact-goat --cli-only
- Verify:
contact-goat-pp-cli --version
- Ensure (or ) is on .
If the
install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.23+):
bash
go install github.com/mvanhorn/printing-press-library/library/sales-and-crm/contact-goat/cmd/contact-goat-pp-cli@latest
If
reports "command not found" after install, the install step did not put the binary on
. Do not proceed with skill commands until verification succeeds.
When to Use This CLI
Reach for this when the user wants:
- coverage of a company (who you already know there, ranked by relationship strength)
- a warm-intro path to a target person (mutual connections across sources)
- prospecting (fan-out search with cross-source dedupe)
- a unified dossier (LinkedIn profile + Happenstance research + optional Deepline enrichment)
- network diffs over time (what's new in your graph in the last N days)
- waterfall enrichment that walks free sources before paid ones
Skip it when the user has a workflow that lives entirely inside LinkedIn Sales Navigator, or when they only need raw LinkedIn scraping with no Happenstance or Deepline overlay (use the LinkedIn MCP directly in that case).
Two Auth Surfaces
Happenstance has two parallel auth paths and the CLI uses both:
| Surface | Auth | Cost | Default? |
|---|
| Cookie web app | Chrome session cookies | Free monthly allocation | YES (auto-prefer) |
| Public REST API | HAPPENSTANCE_API_KEY (Bearer) | 2 credits/search, 1 credit/research | Fallback only |
The auto router prefers cookies until quota is exhausted, then falls back to bearer with an explicit "cost spent" log line on stderr. Use
on
,
,
, or
to opt into bearer explicitly (e.g. for the richer research schema or scoped group searches). Use
to force the cookie surface.
The
subcommands always use the bearer surface and always cost credits. Provision and rotate keys at
https://happenstance.ai/settings/api-keys.
Argument Parsing
- Empty, , or -> run
contact-goat-pp-cli --help
- Starts with and ends with -> MCP installation (see below)
- Starts with -> CLI installation (see below)
- Anything else -> Direct Use (map the request to the best command and run it)
MCP Server Installation
- Install the MCP server:
bash
go install github.com/mvanhorn/printing-press-library/library/sales-and-crm/contact-goat/cmd/contact-goat-pp-mcp@latest
- Register with Claude Code:
bash
claude mcp add -e DEEPLINE_API_KEY=value -e HAPPENSTANCE_API_KEY=value contact-goat-pp-mcp -- contact-goat-pp-mcp
Ask the user for actual values of required API keys before running.
- Verify: .
The MCP server exposes 16 tools. The four bearer-API tools added in this release are:
- - Run a Happenstance public-API search (costs 2 credits)
- - Run a deep-research dossier (costs 1 credit on completion)
- - List Happenstance groups for the caller (free)
- - Show live credit balance and usage history (free)
The other 12 tools cover the cookie surface (search, friends, feed, notifications, dossier, etc.) and the LinkedIn / Deepline integrations.
Direct Use
- Check if installed:
which contact-goat-pp-cli
. If not found, offer CLI installation (above).
- Discover commands:
contact-goat-pp-cli --help
. Drill into subcommand help with contact-goat-pp-cli <command> --help
or contact-goat-pp-cli api hpn <subcommand> --help
.
- Match the user query to the best command (see Notable Commands below).
- Execute with the flag for structured, token-efficient output:
bash
contact-goat-pp-cli <command> [args] --agent
- The flag sets
--json --compact --no-input --no-color --yes
.
Source routing (cookie vs bearer) is automatic. The auto router prefers the free cookie surface and falls back to the paid bearer surface only when cookie quota is exhausted, logging a "cost spent" notice on stderr. Pass
to opt into bearer explicitly (richer schema, group-scoped searches), or
to force cookies.
Enrichment Preflight (read this before running any enrichment command)
These commands spend Deepline credits and REQUIRE
or a BYOK setup:
- (unless you pass and have BYOK providers configured)
- / / /
- / /
Before invoking any of these, verify auth by running doctor first:
bash
contact-goat-pp-cli doctor --agent | grep -i deepline
shows the resolution source:
- — exported in the current shell
- — passed on the command line
set (file:~/.local/deepline/<host>/.env)
— auto-discovered from the official Deepline CLI's persisted key (the user authenticated with or ; no shell export needed)
- — none of the above. Ask the user for a key, or for a BYOK Hunter/Apollo key
The auto-discovery path means a user who has the Deepline CLI installed and authenticated does NOT need to re-export the key into their shell — contact-goat reads
~/.local/deepline/code-deepline-com/.env
directly (mode 0600, owned by the user). Don't ask the user to re-export when
is reported. If
deepline_discovery_skipped
is also reported, those are candidate files the resolver rejected for a security reason (wrong mode, missing prefix); surface them so the user can fix the underlying issue.
Provider chain by target kind (waterfall):
| Target | Primary | Fallback 1 | Fallback 2 |
|---|
| LinkedIn URL | apollo_people_match | hunter_people_find | contactout_enrich_person |
| Email | apollo_people_match | hunter_people_find | - |
| Name + --company | dropleads_email_finder | hunter_email_finder | datagma_find_email |
Notes:
- Name targets MUST pass (or set env).
- Apollo returns when available; treat
email_status: "unavailable"
as "no verified work email on file" (the personal email is still usable).
- Dropleads returns for domains on Google Workspace; the email is a pattern guess, not a verified mailbox.
- Provider-level 403s are surfaced as "Provider not connected" rather than "Check DEEPLINE_API_KEY"; they do not abort the chain. The next provider is tried automatically.
Notable Commands
| Command | What it does |
|---|
| Who you know at a company across LinkedIn + Happenstance, ranked by relationship strength |
coverage --location <city>
| Who you know in a city. Bearer-only (cookie surface has no city-search); use . |
| Happenstance graph people-search (1st / 2nd / 3rd degree). emits flat CSV with semicolon-joined bridges. |
| Fan-out search across LinkedIn + Happenstance (+ opt-in Deepline), deduped |
| Mutual connections across sources who could intro you to a target |
waterfall <target> [--company X]
| Free-sources-first enrichment, falls through to Deepline provider chain. Requires DEEPLINE_API_KEY or --byok. Bare-name targets need --company |
dossier <target> [--enrich-email]
| Unified LinkedIn + Happenstance + (optional) Deepline dossier. --enrich-email requires DEEPLINE_API_KEY |
deepline find-email "<name>" --company <domain>
| Single-call work-email lookup via dropleads_email_finder |
deepline enrich-person <linkedin-url>
| Full person record via apollo_people_match (includes personal_emails[]) |
| Bearer-API search (costs 2 credits, async with poll). keeps only 1st-degree matches; drops weak signals (see docs/scoring.md); auto-paginates. |
api hpn research <description>
| Bearer-API deep dossier (costs 1 credit on completion) |
| Live credit balance, purchases, recent usage events (free) |
| Check CLI health, both Happenstance surfaces, LinkedIn, and Deepline. Reports happenstance_graph_status
(ok / stale / very_stale) on the LinkedIn upload age. |
Run any command with
for full flag documentation.
Agent Mode
Add
to any command. Expands to:
--json --compact --no-input --no-color --yes
.
- Pipeable — JSON on stdout, errors on stderr
- Filterable — keeps a subset of fields, with dotted-path support (see below)
- Previewable — shows the request without sending
- Cacheable — GET responses cached for 5 minutes, bypass with
- Non-interactive — never prompts, every input is a flag
Filtering output
accepts dotted paths to descend into nested responses; arrays traverse element-wise:
bash
contact-goat-pp-cli <command> --agent --select id,name
contact-goat-pp-cli <command> --agent --select items.id,items.owner.name
Use this to narrow huge payloads to the fields you actually need — critical for deeply nested API responses.
Response envelope
Data-layer commands wrap output in
{"meta": {...}, "results": <data>}
. Parse
for data and
to know whether it's
or local. The
summary is printed to stderr only when stdout is a TTY; piped/agent consumers see pure JSON on stdout.
Exit Codes
| Code | Meaning |
|---|
| 0 | Success |
| 2 | Usage error (wrong arguments) |
| 3 | Resource not found |
| 4 | Authentication required |
| 5 | API error (upstream issue, including bearer 402 out-of-credits) |
| 7 | Rate limited (cookie 429 or bearer 429; auto-fallback may apply) |