Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
52a57ed
Merge pull request #74 from trycompai/main
carhartlewis Aug 7, 2026
1561073
chore: release release
github-actions[bot] Aug 7, 2026
5074fc4
Merge pull request #75 from trycompai/release-please--branches--release
carhartlewis Aug 7, 2026
3c20d80
Merge pull request #77 from trycompai/main
carhartlewis Aug 7, 2026
808b835
Merge pull request #79 from trycompai/main
carhartlewis Aug 7, 2026
407280a
Merge pull request #81 from trycompai/main
carhartlewis Aug 7, 2026
c26a08d
Merge pull request #84 from trycompai/main
carhartlewis Aug 7, 2026
d585dc3
Merge pull request #90 from trycompai/main
carhartlewis Aug 8, 2026
d0299d9
Merge pull request #98 from trycompai/main
carhartlewis Aug 11, 2026
7d4a573
Merge pull request #107 from trycompai/main
carhartlewis Aug 11, 2026
56f4eeb
Merge pull request #116 from trycompai/main
github-actions[bot] Aug 11, 2026
57001e6
Merge pull request #119 from trycompai/main
github-actions[bot] Aug 11, 2026
ad1d702
Merge pull request #122 from trycompai/main
github-actions[bot] Aug 11, 2026
fc0c594
Merge pull request #127 from trycompai/main
github-actions[bot] Aug 11, 2026
4ffe150
Merge pull request #130 from trycompai/main
github-actions[bot] Aug 11, 2026
14cd220
Merge pull request #135 from trycompai/main
github-actions[bot] Aug 11, 2026
f2484fb
Merge pull request #141 from trycompai/main
github-actions[bot] Aug 12, 2026
bb63520
Merge pull request #161 from trycompai/main
github-actions[bot] Aug 18, 2026
517d859
Merge pull request #165 from trycompai/main
github-actions[bot] Aug 20, 2026
b842bd6
Merge pull request #168 from trycompai/main
github-actions[bot] Aug 20, 2026
77089e4
Merge pull request #172 from trycompai/main
github-actions[bot] Aug 20, 2026
6d4793d
Merge pull request #177 from trycompai/main
github-actions[bot] Aug 21, 2026
cb257d1
fix(dev): stop the tRPC watcher self-triggering on Linux
claude Sep 2, 2026
11069d5
chore(claude): install Agent Reach on remote session start (#1)
teknewmcc26 Sep 2, 2026
70bdb4c
Merge remote-tracking branch 'origin/release' into claude/trycompai-c…
claude Sep 2, 2026
21c53e5
chore(claude): register the CRM dev hook on remote session start
claude Sep 2, 2026
dd70fab
Merge pull request #2 from teknewmcc26/claude/trycompai-crm-setup-yox5ez
teknewmcc26 Sep 2, 2026
1b2ccae
fix(deploy): daily crons so the Hobby plan accepts the build
claude Sep 2, 2026
28897b6
fix(app): let the Vercel build see API_URL and APP_URL
claude Sep 2, 2026
9077b99
feat(auth): optional email and password sign-in
claude Sep 2, 2026
ab433a6
Merge branch 'claude/password-sign-in-yox5ez' into claude/prod-yox5ez
claude Sep 2, 2026
ff32c57
Merge pull request #5 from teknewmcc26/claude/prod-yox5ez
teknewmcc26 Sep 2, 2026
c42c22a
feat(agent): GLEIF M&A sourcing tools and skill
claude Sep 2, 2026
4917357
fix(telemetry): allow the gleif tool names
claude Sep 3, 2026
0e0d4cc
fix(app): narrate the gleif tools in the agent transcript
claude Sep 3, 2026
3063dd1
feat(agent): add companies with their source, and look up work email
claude Sep 3, 2026
b09d4b5
Merge pull request #6 from teknewmcc26/claude/gleif-sourcing-yox5ez
teknewmcc26 Sep 3, 2026
eb8587d
feat(agent): contact details from Hunter, Apollo, Lusha, Dropcontact …
claude Sep 3, 2026
a8fb7f9
fix(agent): retireExhausted never exceeds its limit
claude Sep 3, 2026
e1597bd
Merge pull request #8 from teknewmcc26/claude/retire-limit-yox5ez
teknewmcc26 Sep 3, 2026
9989709
Merge pull request #7 from teknewmcc26/claude/contact-providers-yox5ez
teknewmcc26 Sep 3, 2026
ccaceb6
feat(agent): the employer's website as the last contact-details provider
claude Sep 3, 2026
559d1b2
Merge pull request #10 from teknewmcc26/claude/web-provider-yox5ez
teknewmcc26 Sep 3, 2026
5ca8375
feat(agent): SEC EDGAR research through an external edgartools service
claude Sep 3, 2026
dc8765e
Merge pull request #11 from teknewmcc26/claude/sec-edgar-yox5ez
teknewmcc26 Sep 3, 2026
cd14832
feat(app): a Research → SEC page on the edgar service
claude Sep 3, 2026
223ff5f
Merge pull request #12 from teknewmcc26/claude/sec-page-yox5ez
teknewmcc26 Sep 3, 2026
f9c972c
Merge pull request #13 from teknewmcc26/claude/sec-edgar-yox5ez
teknewmcc26 Sep 3, 2026
936b199
feat(edgar): tunnel.sh runs the service behind a Cloudflare tunnel on…
claude Sep 3, 2026
c5568b0
Merge pull request #14 from teknewmcc26/claude/edgar-tunnel-yox5ez
teknewmcc26 Sep 3, 2026
560151d
fix(agent): lock the claimed and retired rows once, in a materialized…
claude Sep 3, 2026
4e20f01
Merge pull request #15 from teknewmcc26/claude/retire-limit-cte-yox5ez
teknewmcc26 Sep 3, 2026
42cff5c
test(agent): name the rows when retireExhausted exceeds its limit
claude Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .claude/hooks/crm-dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash
set -euo pipefail

if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fi

cd "$CLAUDE_PROJECT_DIR"

NODE_DIR=/opt/node24
if [ ! -x "$NODE_DIR/bin/node" ]; then
VERSION=$(curl -sSL https://nodejs.org/dist/index.json | python3 -c 'import sys,json; print(next(v["version"] for v in json.load(sys.stdin) if v["version"].startswith("v24.")))')
mkdir -p "$NODE_DIR"
curl -sSL "https://nodejs.org/dist/$VERSION/node-$VERSION-linux-x64.tar.xz" | tar -xJ -C "$NODE_DIR" --strip-components=1
fi
export PATH="$NODE_DIR/bin:$PATH"
echo "export PATH=\"$NODE_DIR/bin:\$PATH\"" >> "$CLAUDE_ENV_FILE"

if [ ! -f .env ]; then
cp .env.example .env
sed -i "s|^BETTER_AUTH_SECRET=\"\"|BETTER_AUTH_SECRET=\"$(openssl rand -base64 32)\"|" .env
sed -i "s|^# AGENT_URL=\"http://127.0.0.1:2000\"|AGENT_URL=\"http://127.0.0.1:2000\"|" .env
sed -i "s|^# AGENT_BRIDGE_SECRET=\"\"|AGENT_BRIDGE_SECRET=\"$(openssl rand -base64 32)\"|" .env
sed -i "s|^ALLOWED_SIGN_IN=\"\"|ALLOWED_SIGN_IN=\"localhost\"|" .env
fi

if ! docker info >/dev/null 2>&1; then
nohup dockerd >/tmp/dockerd.log 2>&1 &
for _ in $(seq 1 30); do
docker info >/dev/null 2>&1 && break
sleep 1
done
fi

docker compose up -d
for _ in $(seq 1 60); do
[ "$(docker inspect -f '{{.State.Health.Status}}' crm-postgres 2>/dev/null)" = "healthy" ] && break

@cubic-dev-ai cubic-dev-ai Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When Postgres never becomes healthy, this loop still completes successfully and the hook runs migrations and seeding against an unavailable database. Check the health status after the loop and exit with a clear error before running database commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/hooks/crm-dev.sh, line 37:

<comment>When Postgres never becomes healthy, this loop still completes successfully and the hook runs migrations and seeding against an unavailable database. Check the health status after the loop and exit with a clear error before running database commands.</comment>

<file context>
@@ -0,0 +1,43 @@
+
+docker compose up -d
+for _ in $(seq 1 60); do
+  [ "$(docker inspect -f '{{.State.Health.Status}}' crm-postgres 2>/dev/null)" = "healthy" ] && break
+  sleep 1
+done
</file context>
Fix with cubic

sleep 1
done

bun install
bun run --filter=@crm/db db:deploy

@cubic-dev-ai cubic-dev-ai Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: A remote session with .env.local or DATABASE_URL runs migrations against that database instead of the generated local Postgres. Add a local-database check before this command or force the generated localhost URL.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/hooks/crm-dev.sh, line 42:

<comment>A remote session with `.env.local` or `DATABASE_URL` runs migrations against that database instead of the generated local Postgres. Add a local-database check before this command or force the generated localhost URL.</comment>

<file context>
@@ -0,0 +1,43 @@
+done
+
+bun install
+bun run --filter=@crm/db db:deploy
+bun run --filter=@crm/db db:seed
</file context>
Fix with cubic

bun run --filter=@crm/db db:seed
98 changes: 98 additions & 0 deletions .claude/hooks/session-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash
set -uo pipefail

if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fi

AGENT_REACH_HOME="$HOME/.agent-reach"
AGENT_REACH_TOOLS="$AGENT_REACH_HOME/tools"
AGENT_REACH_VENV="$HOME/.agent-reach-venv"
AGENT_REACH_REPO="https://github.com/Panniantong/agent-reach.git"
XHS_REPO="https://github.com/xpzouying/xiaohongshu-mcp.git"
XHS_PORT=18060
YTDLP_CONFIG="$HOME/.config/yt-dlp/config"
MCPORTER_CONFIG="$HOME/.mcporter/mcporter.json"
LOCAL_BIN="$HOME/.local/bin"

export PATH="$AGENT_REACH_VENV/bin:$LOCAL_BIN:$PATH"

log() { echo "[agent-reach hook] $*"; }

step() {
local name="$1"
shift
if "$@"; then
log "ok: $name"
else
log "failed: $name (continuing)"
fi
}

install_agent_reach() {
mkdir -p "$AGENT_REACH_TOOLS"
if [ ! -d "$AGENT_REACH_TOOLS/agent-reach/.git" ]; then
git clone -q --depth 1 "$AGENT_REACH_REPO" "$AGENT_REACH_TOOLS/agent-reach"

@cubic-dev-ai cubic-dev-ai Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Every remote session executes mutable upstream code without revision or integrity checks. Pin repository commits and package versions, then verify hashes before installing them.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/hooks/session-start.sh, line 35:

<comment>Every remote session executes mutable upstream code without revision or integrity checks. Pin repository commits and package versions, then verify hashes before installing them.</comment>

<file context>
@@ -0,0 +1,98 @@
+install_agent_reach() {
+  mkdir -p "$AGENT_REACH_TOOLS"
+  if [ ! -d "$AGENT_REACH_TOOLS/agent-reach/.git" ]; then
+    git clone -q --depth 1 "$AGENT_REACH_REPO" "$AGENT_REACH_TOOLS/agent-reach"
+  else
+    git -C "$AGENT_REACH_TOOLS/agent-reach" pull -q --ff-only || true
</file context>
Fix with cubic

else
git -C "$AGENT_REACH_TOOLS/agent-reach" pull -q --ff-only || true
fi
[ -x "$AGENT_REACH_VENV/bin/pip" ] || python3 -m venv "$AGENT_REACH_VENV"
"$AGENT_REACH_VENV/bin/pip" install -q "$AGENT_REACH_TOOLS/agent-reach"
}

install_apt_tools() {
local missing=()
command -v gh >/dev/null || missing+=(gh)
command -v ffmpeg >/dev/null || missing+=(ffmpeg)
[ "${#missing[@]}" -eq 0 ] && return 0
apt-get update -q >/dev/null 2>&1
DEBIAN_FRONTEND=noninteractive apt-get install -y -q "${missing[@]}" >/dev/null 2>&1
}

install_mcporter() {
command -v mcporter >/dev/null || npm install -g mcporter >/dev/null 2>&1
}

mcporter_has() {
[ -f "$MCPORTER_CONFIG" ] && grep -q "\"$1\"" "$MCPORTER_CONFIG"
}

configure_mcporter() {
mcporter_has exa || mcporter config add exa https://mcp.exa.ai/mcp --scope home >/dev/null
mcporter_has linkedin || mcporter config add linkedin --command uvx --arg mcp-server-linkedin@latest --env UV_HTTP_TIMEOUT=300 --scope home >/dev/null
mcporter_has xiaohongshu || mcporter config add xiaohongshu "http://localhost:$XHS_PORT/mcp" --scope home >/dev/null

@cubic-dev-ai cubic-dev-ai Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The hook registers XiaoHongShu's localhost endpoint but never starts the binary that serves it, so every XiaoHongShu MCP request fails. Start and supervise the server before registering it, or configure mcporter to launch the built binary.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/hooks/session-start.sh, line 63:

<comment>The hook registers XiaoHongShu's localhost endpoint but never starts the binary that serves it, so every XiaoHongShu MCP request fails. Start and supervise the server before registering it, or configure mcporter to launch the built binary.</comment>

<file context>
@@ -0,0 +1,98 @@
+configure_mcporter() {
+  mcporter_has exa || mcporter config add exa https://mcp.exa.ai/mcp --scope home >/dev/null
+  mcporter_has linkedin || mcporter config add linkedin --command uvx --arg mcp-server-linkedin@latest --env UV_HTTP_TIMEOUT=300 --scope home >/dev/null
+  mcporter_has xiaohongshu || mcporter config add xiaohongshu "http://localhost:$XHS_PORT/mcp" --scope home >/dev/null
+}
+
</file context>
Fix with cubic

}

configure_ytdlp() {
mkdir -p "$(dirname "$YTDLP_CONFIG")"
grep -qxF -- '--js-runtimes node' "$YTDLP_CONFIG" 2>/dev/null || printf '%s\n' '--js-runtimes node' >> "$YTDLP_CONFIG"
}

install_channels() {
agent-reach install --env=auto --system --channels=all >/dev/null 2>&1 || true
return 0
}

build_xiaohongshu() {
[ -x "$AGENT_REACH_TOOLS/xiaohongshu-mcp" ] && return 0
command -v go >/dev/null || return 1
[ -d "$AGENT_REACH_TOOLS/xiaohongshu-mcp-src/.git" ] || git clone -q --depth 1 "$XHS_REPO" "$AGENT_REACH_TOOLS/xiaohongshu-mcp-src"
(cd "$AGENT_REACH_TOOLS/xiaohongshu-mcp-src" && CGO_ENABLED=0 go build -o "$AGENT_REACH_TOOLS/xiaohongshu-mcp" . && CGO_ENABLED=0 go build -o "$AGENT_REACH_TOOLS/xiaohongshu-login" ./cmd/login) >/dev/null 2>&1
}

export_path() {
[ -n "${CLAUDE_ENV_FILE:-}" ] || return 0
echo "export PATH=\"$AGENT_REACH_VENV/bin:$LOCAL_BIN:\$PATH\"" >> "$CLAUDE_ENV_FILE"
}

step "agent-reach package" install_agent_reach
step "gh + ffmpeg" install_apt_tools
step "mcporter" install_mcporter
step "mcporter servers" configure_mcporter
step "yt-dlp config" configure_ytdlp
step "optional channels" install_channels
step "xiaohongshu-mcp build" build_xiaohongshu
step "PATH" export_path

agent-reach doctor 2>/dev/null | grep -E '^状态' || true
exit 0
16 changes: 16 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,21 @@
},
"enabledPlugins": {
"paper-desktop@paper": true
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/crm-dev.sh"
}
]
}
]
}
}
50 changes: 50 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ GOOGLE_CLIENT_SECRET=""
# SLACK_CLIENT_ID=""
# SLACK_CLIENT_SECRET=""

# Optional. Adds an email + password form to the sign-in page, next to the
# social buttons. Only addresses that pass ALLOWED_SIGN_IN can create an
# account, exactly like the social sign-ins, and the password must be at
# least 8 characters. The only value that turns it on is "true".
# PASSWORD_SIGN_IN="true"

# Which Entra tenant may sign in. "common" (the default) accepts any work,
# school or personal Microsoft account and leans on ALLOWED_SIGN_IN to decide
# who actually gets in; your own tenant's GUID refuses everyone else at
Expand Down Expand Up @@ -125,6 +131,50 @@ GOOGLE_CLIENT_SECRET=""
# knowing before a call. https://perplexity.ai/settings/api
# PERPLEXITY_API_KEY=""

# Contact-data providers. Each one is optional and the agent asks the ones
# that are set, in this order, stopping at the first confident answer:
# Hunter, Apollo, Lusha, Dropcontact, ZoomInfo. Every answer is written to
# the contact's timeline with its confidence and its source.
#
# SEC EDGAR research — US public companies from their SEC filings: profile,
# filings, 5%+ shareholders, insider transactions, the proxy statement with
# its executives and their pay. Served by services/edgar (Python, edgartools)
# and free. `docker compose up -d` runs it on port 2100; a Colab notebook or
# another machine can run it too, see services/edgar/README.md. Without
# EDGAR_URL the sec_* tools say the source is unavailable.
# EDGAR_URL="http://127.0.0.1:2100"
#
# Shared secret between the CRM and the service. Optional on loopback; set it
# whenever the service is reachable from elsewhere.
# EDGAR_SECRET=""
#
# The SEC requires every automated client to identify itself. Any real email.
# Read by the service, not by the CRM.
# EDGAR_IDENTITY="Jane Doe jane@example.com"
#
# Hunter — a work email with the public pages it was seen on, and a
# deliverability check. The free plan covers a few dozen lookups a month.
# https://hunter.io/api-keys
# HUNTER_API_KEY=""
#
# Apollo — a work email with its verification status, title and work phone.
# https://app.apollo.io/#/settings/integrations/api
# APOLLO_API_KEY=""
#
# Lusha — work email, direct and mobile phones, title.
# https://dashboard.lusha.com/enrich/api
# LUSHA_API_KEY=""
#
# Dropcontact — work email with its qualification, phone, title. GDPR-compliant
# by construction; the lookup is asynchronous and takes a few seconds.
# https://app.dropcontact.com/api
# DROPCONTACT_API_KEY=""
#
# ZoomInfo — work email, direct and mobile phones, title. Needs a ZoomInfo API
# user; both halves must be set, and a token is minted from them and cached.
# ZOOMINFO_USERNAME=""
# ZOOMINFO_PASSWORD=""

# GitHub — raises the rate limit when matching contacts to GitHub profiles.
# Any classic token with no scopes will do.
# GITHUB_TOKEN=""
Expand Down
103 changes: 103 additions & 0 deletions apps/agent/agent/lib/apollo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { z } from "zod";
import {
type ContactDetails,
fetchJson,
keyed,
type Outcome,
type Person,
type Provider,
} from "./contact-details";
import { CONTACT_DETAILS } from "./contact-details-config";

export const APOLLO_API_KEY = "APOLLO_API_KEY";

const phone = z.object({
sanitized_number: z.string().trim().min(1).nullable().optional(),
raw_number: z.string().trim().min(1).nullable().optional(),
type: z.string().nullable().optional(),
});

const match = z.object({
person: z
.object({
id: z.string().nullable().optional(),
email: z.string().trim().email().nullable().optional(),
email_status: z.string().nullable().optional(),
title: z.string().nullable().optional(),
linkedin_url: z.string().nullable().optional(),
phone_numbers: z.array(phone).nullable().optional(),
})
.nullable()
.optional(),
});

function confidenceOf(status: string | null | undefined): number {
const scale = CONTACT_DETAILS.apollo.confidence;
switch (status) {
case "verified":
return scale.verified;
case "likely_to_engage":
case "likely":
return scale.likely;
case "guessed":
case "extrapolated":
return scale.guessed;
default:
return scale.unknown;
}
}

export async function apolloMatch(
person: Person,
): Promise<Outcome<ContactDetails>> {
const apiKey = process.env[APOLLO_API_KEY]?.trim();
if (!apiKey) return { ok: false, reason: `No ${APOLLO_API_KEY}.` };

const response = await fetchJson(
new URL(`${CONTACT_DETAILS.apollo.baseUrl}/people/match`),
{
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": apiKey,
},
body: JSON.stringify({
first_name: person.firstName.trim(),
last_name: person.lastName.trim(),
domain: person.domain.trim().toLowerCase(),
organization_name: person.companyName ?? undefined,
reveal_personal_emails: false,
reveal_phone_number: false,

@cubic-dev-ai cubic-dev-ai Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: With an Apollo key configured, this flag disables phone-number revelation, so apolloMatch cannot return the work phone promised by the provider. Set reveal_phone_number to true.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/agent/agent/lib/apollo.ts, line 70:

<comment>With an Apollo key configured, this flag disables phone-number revelation, so `apolloMatch` cannot return the work phone promised by the provider. Set `reveal_phone_number` to `true`.</comment>

<file context>
@@ -0,0 +1,103 @@
+				domain: person.domain.trim().toLowerCase(),
+				organization_name: person.companyName ?? undefined,
+				reveal_personal_emails: false,
+				reveal_phone_number: false,
+			}),
+		},
</file context>
Suggested change
reveal_phone_number: false,
reveal_phone_number: true,
Fix with cubic

}),
},
match,
"Apollo",
);
if (!response.ok) return response;

const found = response.data.person;
return {
ok: true,
data: {
provider: "apollo",
email: found?.email ?? null,
confidence: found?.email ? confidenceOf(found.email_status) : 0,
phones: (found?.phone_numbers ?? []).flatMap((entry) => {
const number = entry.sanitized_number ?? entry.raw_number;
return number ? [{ number, type: entry.type ?? null }] : [];
}),
title: found?.title ?? null,
linkedinUrl: found?.linkedin_url ?? null,
sources: [],
reference: found?.id ?? null,
},
};
}

export const apollo: Provider = {
id: "apollo",
label: "Apollo",
keys: [APOLLO_API_KEY],
enabled: keyed(APOLLO_API_KEY),
find: apolloMatch,
};
40 changes: 40 additions & 0 deletions apps/agent/agent/lib/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ export function capabilitiesFrom(
"a person read back from a LinkedIn URL you already hold — their real name, bio, current title and employer, every earlier role with its dates, their education and their other public profiles, all self-reported and so authoritative on identity",
enabled: contextDev !== null,
},
{
...fromEnv("HUNTER_API_KEY"),
label: "Contact details via Hunter",
gives:
"a person's work email from their name and their employer's domain, with the public pages Hunter saw it on, and a deliverability check on an address you already hold",
},
{
...fromEnv("APOLLO_API_KEY"),
label: "Contact details via Apollo",
gives:
"a person's work email with Apollo's verification status, their title and a work phone",
},
{
...fromEnv("LUSHA_API_KEY"),
label: "Contact details via Lusha",
gives: "a person's work email, direct and mobile phones and their title",
},
{
...fromEnv("DROPCONTACT_API_KEY"),
label: "Contact details via Dropcontact",
gives:
"a person's work email with its qualification, a phone and their title, from a GDPR-compliant source",
},
{
id: "ZOOMINFO_USERNAME",
from: "ZOOMINFO_USERNAME + ZOOMINFO_PASSWORD",
label: "Contact details via ZoomInfo",
gives:
"a person's work email, direct and mobile phones and their title from ZoomInfo's database",
enabled: Boolean(
process.env.ZOOMINFO_USERNAME?.trim() &&
process.env.ZOOMINFO_PASSWORD?.trim(),
),
},
{
...fromEnv("EDGAR_URL"),
label: "SEC EDGAR research",
gives:
"US public companies from SEC filings: profile, filings, 5%+ shareholders, insider transactions, the proxy statement with its executives and their pay, all free and with a filing URL to cite",
},
{
...fromEnv("BLOB_READ_WRITE_TOKEN"),
label: "Picture storage",
Expand Down
Loading
Loading