Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Scout

Private company intelligence for investors, founders, and startups. Scout uses Gemini AI to generate rich profiles for any organization or person in the startup and VC ecosystem, and persists everything it learns to a Cloudflare D1 database so repeat lookups are instant.


What it does

Search — type any company name, fund, or person. Scout queries Gemini and returns up to five matching organizations and five matching people with descriptions and metadata.

Organization detail — full profile for a company or VC firm: description, funding history (rounds, amounts, lead investors), portfolio companies (for investors), key team members, and source links.

Person detail — full profile for a founder, partner, or executive: bio, location, complete job history with dates, and source links.

AI-assisted lookup — if a name isn't in the database yet, Scout surfaces an "AI look up" flow. For organizations you can paste a website URL; for people you can paste a LinkedIn URL. These hints are forwarded to Gemini for more accurate results.

Refresh — the Edit button in the navbar triggers a fresh Gemini call for any org or person, then saves the updated record back to D1.

D1 persistence — every org and person fetched from Gemini is normalized and written to Cloudflare D1. The next request for the same slug reads from D1 instantly with no AI call needed.


Architecture

scout/
├── frontend/          React + Vite + Tailwind SPA
│   └── src/
│       ├── pages/     Home, OrgDetail, PersonDetail
│       ├── components/ Navbar, SearchCommand, shadcn/ui primitives
│       ├── lib/       api.ts — fetch wrapper + localStorage org cache
│       └── types/     index.ts — all shared TypeScript types
├── worker/            Cloudflare Worker (Hono)
│   ├── schema.sql     D1 table definitions (run once to provision)
│   ├── wrangler.toml  Cloudflare deployment config + D1 binding
│   └── src/
│       ├── index.ts   Hono app, route mounting, Env type
│       ├── helpers.ts Gemini API client + system prompts (TOON format)
│       ├── db.ts      D1 read/write helpers (getOrg, saveOrg, getPerson, savePerson)
│       └── routes/
│           ├── search.ts  GET /api/search?q=
│           ├── orgs.ts    GET /api/orgs/:slug, POST /api/orgs/:slug/refresh
│           └── people.ts  GET /api/people/:slug, POST /api/people/:slug/refresh
└── mock/              Static Node.js mock server for local dev (no Gemini quota)
    ├── server.mjs     Mirrors worker routes using fixture data
    └── data.json      Fixture: Nophin, Y Combinator, Teddy Li

Request flow

User navigates to /org/:slug
  → frontend: GET /api/orgs/:slug
  → worker: check D1 for slug
      hit  → return stored OrgDetail immediately
      miss → callGemini(slug, COMPANY|INVESTOR_SYSTEM_PROMPT)
               → decode TOON response → OrgDetail
               → waitUntil(saveOrgToDB(DB, result))  ← non-blocking
               → return OrgDetail

User clicks Refresh (Edit button)
  → frontend: POST /api/orgs/:slug/refresh
  → worker: callGemini (always, bypasses D1)
               → decode → OrgDetail
               → waitUntil(saveOrgToDB(DB, result))  ← overwrites old record
               → return OrgDetail

The url= and linkedin= disambiguation params bypass the D1 cache (the hint implies the user wants a specific, possibly different result than what's stored).


D1 Database

Schema

Seven normalized SQLite tables:

Table Contents
organizations Companies, VC firms, funds
people Founders, partners, executives
person_org_jobs Employment records linking people → orgs
funding_rounds Fundraising rounds for companies
funding_round_investors Investors participating in each round
investments Investor portfolio entries (investor → company)
sources Source URLs attached to orgs or people

Upsert strategy

  • Root records (organizations, people) use INSERT OR REPLACE.
  • Child rows (rounds, jobs, sources) are deleted and re-inserted on every save so stale data never lingers (e.g. a team member who left).
  • Secondary records that arrive nested in a response — portfolio company stubs, job org stubs, team member stubs — are saved with INSERT OR IGNORE so a previously fetched full record is never downgraded to partial data.

Provisioning

# 1. Create the database (one-time)
cd worker
npx wrangler d1 create scout

# 2. Paste the returned database_id into wrangler.toml under [[d1_databases]]

# 3. Apply schema to the remote database
npx wrangler d1 execute scout --remote --file=schema.sql

# 4. Apply schema to the local dev database
npx wrangler d1 execute scout --local --file=schema.sql

Local development

Prerequisites

  • Node.js 18+
  • A Gemini API key (Google AI Studio)
  • A Cloudflare account with wrangler authenticated (npx wrangler login)

Install

npm install

Option A — mock server (no Gemini quota)

Returns static fixture data for Nophin, Y Combinator, and Teddy Li. No API keys required.

# Terminal 1: mock worker API on :8787
npm run dev:mock

# Terminal 2: Vite dev server on :5173 (proxies /api → :8787)
npm run dev

Option B — live worker (real Gemini calls + D1)

# 1. Create worker/.dev.vars (gitignored)
echo "GEMINI_API_KEY=your_key_here" > worker/.dev.vars

# 2. Terminal 1: wrangler dev on :8787 (uses local D1 SQLite)
npm run dev:worker

# 3. Terminal 2: Vite dev server
npm run dev

Environment variables

Worker — set in worker/.dev.vars for local dev; use npx wrangler secret put for production:

Variable Description
GEMINI_API_KEY Google Gemini API key

Frontend — copy frontend/.env.example to frontend/.env.local:

Variable Description
VITE_LOGO_DEV_PUBLISHABLE_KEY Logo.dev publishable key for org logos (optional)

Deployment

# Build and deploy the worker (includes D1 binding)
npm run build:worker
npx wrangler deploy --cwd worker

# Build the frontend (deploy separately to Cloudflare Pages or any static host)
npm run build:frontend

The frontend vite.config.ts proxies /api to http://localhost:8787 in dev. In production, deploy the worker and frontend to the same Cloudflare account so the Pages project can route /api/* to the worker via a custom route.


Tech stack

Layer Tech
Frontend React 18, Vite, Tailwind CSS, shadcn/ui, React Router
Worker Cloudflare Workers, Hono, TypeScript
AI Google Gemini (gemini-3-flash-preview) via REST, responses in TOON format
Database Cloudflare D1 (SQLite at the edge)
Logos Logo.dev

License

MIT © TXL. See LICENSE.

About

Private company intelligence for investors, founders, and startups

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages