Exa web search for swamp: any search, plus a bulk people-to-LinkedIn finder that never adopts a namesake
  • TypeScript 100%
Find a file
keeb 350f75be6d @keeb/exa: Exa web search and people finder
Two methods on one model:
- search: any Exa search; results, highlights, optional text and cost.
- find_people: one Exa people-category search per person, each
  linkedin.com/in candidate scored against employer, corporate email
  domain, location and GitHub handle. A name-only match is never picked.
  Headline, location and current role are parsed from the profile text.
  Each person is written as their search returns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:26:56 -07:00
extensions/models @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
.gitignore @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
.swamp.yaml @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
CLAUDE.md @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
LICENSE.txt @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
manifest.yaml @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00
README.md @keeb/exa: Exa web search and people finder 2026-10-24 17:26:56 -07:00

@keeb/exa

Exa web search for swamp. Run any Exa search, or find a list of people's LinkedIn profiles in one execution.

Model

Model Method What it does
@keeb/exa search One Exa search; results (title, url, highlights, optional text) and cost
find_people One people search per person; scored LinkedIn candidates and a best pick

find_people

Input is a list of people, inline (people) or as a JSON file (peopleFile):

[{ "key": "jane", "name": "Jane Doe", "email": "jane@acme.com", "company": "Acme", "location": "Berlin", "github": "janedoe" }]

Only key and name are required. The query is the quoted name plus the company, the email domain's organisation (freemail domains are dropped), and the location.

Every linkedin.com/in/ result is scored against what you passed in:

  • confirmed — name, plus employer, corporate email domain, or GitHub handle
  • likely — name, plus location
  • namesake-risk — name only
  • no-name-match — the name isn't in the result

best is the strongest confirmed or likely candidate, else null. A name-only match is never picked. An API error for one person is recorded on that person and the run continues.

Each candidate also carries headline, location, and currentRole (Staff Engineer @ Acme), parsed from the profile text Exa returns.

Writes person/<key> per person as each search returns (versioned; each run appends), so a run stopped midway keeps what it found. Then a people/<label> digest with counts by verdict and total cost.

Setup

swamp vault create local_encryption exa
printf '%s' "$EXA_API_KEY" | swamp vault put exa apiKey

swamp model create @keeb/exa exa
# globalArguments:
#   apiKey: ${{ vault.get(exa, apiKey) }}

swamp model method run exa search --input query='open source workflow engines'
swamp model method run exa find_people --input peopleFile=people.json --input label=batch-1

License

MIT