mo-root/open-kb

Plug in one domain. Get a full market map and a knowledge graph that plugs straight into your agent. Agents search the job instead of the brand name, read every host's own page, and cite it.

11

stars

323

commits

TypeScript

primary language

Sep 10, 2026

updated

open-kb-demo.vercel.app
ai-agents
competitive-intelligence
go-to-market
knowledge-graph
market-intelligence
market-research
nextjs
typescript
web-scraping

README

open·knowledge base

One domain in, knowledge base out

License: MIT Node.js >=20

→ Try the beta

Point it at your domain and it maps the whole market — competitors, substitutes, integrations, buyers, and where the market argues. It never searches the company's name: it works out the job each product does and searches for the job. Every claim carries a URL and a literal quote from a page the run fetched, and the map exports as a folder of markdown your agent can walk, with llms.txt at the door.

The launch film: twenty known domains stream past, yourcompany.com snaps into place, its glyphs detonate into de-branded queries, settle into a rotating market orbit, crystallize into a labeled knowledge graph, and plug into an agent — one domain in, knowledge base out

The launch film — watch it with sound

Quickstart

Node 20+, a Bright Data account with a SERP and an Unlocker zone, and an OpenRouter key.

git clone https://github.com/mo-root/open-kb.git && cd open-kb && pnpm install
cp .env.example .env      # four keys, named in the file
pnpm sweep yourcompany.com
runs/sweep-yourcompany-com-<stamp>.json   every entity, edge and span

runs/exports/kb-yourcompany-com/          pnpm run export <run>
├── entities/     one file per company, with its quotes
├── relations/    one file per relation found: adjacent, competitor, substitute …
├── segments/     each market, and who is in it
└── llms.txt      the door an agent comes in through

Why those two accounts. Bright Data because a map is only as good as what comes back: across the 17 sweeps in runs/, 11–15% of hosts stayed unreadable after a direct fetch and one Web Unlocker escalation, and those stay on the map wearing the reason rather than vanishing from it. OpenRouter because the judgement does not need a frontier model: in the bake-off — five configs, one company, ten queries each — the DeepSeek flash default came in cheapest per entity at $0.00065, against $0.0008 for the next best and $0.002 for the dearest config that beat it on volume. Two configs did find roughly 2.4x more entities for 3.5x and 7.7x the money; the default wins on cost per entity and on the recall probe, at the same description grounding. That is why the cheap model is the default and the spend caps are sized for it — not a claim that it finds the most.

The agents

One judgement each, every answer in a schema. Each is a markdown prompt in prompts/ — changing how the engine thinks is a text edit. Six run on every sweep:

agentownsruns
understandwhat the company sells, and which products share a marketonce per run
cataloga product's de-branded queries — the job, never the nameonce per product
assesswiden, deepen or stop, racing the searchup to eight times
classifywhat a host is, with its page in handonce per host on the default path
linkhow two entities relate40 pairs a call
orphana relation for an entity no pair reached20 at a time

Three more run BY DEFAULT since 2026-08-22 — each survived an A/B on a stored run and each has an opt-OUT environment variable: listicle-harvest mines the vendor names a roundup already printed (OPENKB_LISTICLE_HARVEST=0 turns it off — found Windsurf, Zed, Tabnine, Codeium, Aider and Continue on cursor.com with zero direct SERP hits, and 18 real vendors on grundfos.com); triage skips hosts from search metadata before a fetch is spent (OPENKB_TRIAGE=0 — 4.6% of hosts skipped, pooled over the 28 runs that record it, 1,283 of 28,182; per-market it ranges 0.3% to 13.3%); second-look re-asks classify itself against a deeper page for hosts left unknown (OPENKB_SECOND_LOOK=0 — 716 asked and 324 rescued over those same runs; a third of the asks never get a page at all). Two more stay opt-in, one environment variable each: discover and group replace the single understand call (OPENKB_DISCOVERY=agent); drop-confirm gives every settled none a second batched opinion (OPENKB_DROP_CONFIRM=1) — its own A/B did not survive, rescuing 0 of 12, 0 of 27 and 5 of 29 across three runs.

flowchart TD
    D[domain] --> U["understand<br/>reads the site"]
    U --> C["catalog<br/>per product, in parallel"]
    C --> Q["query queue"]
    Q --> W["SERP worker pool<br/><i>every hit tagged with its query</i>"]
    W --> A{"assess"}
    A -->|"widen: more queries"| Q
    A -->|"deepen: 2 pages to 4"| Q
    A -->|"enough"| H["listicle-harvest<br/><i>default on</i>"]
    H --> T["triage<br/><i>default on — skip before fetching</i>"]
    T --> K["classify<br/>page in hand"]
    K --> S["second-look · drop-confirm<br/><i>second-look default on · drop-confirm opt-in</i>"]
    S --> L["link"] --> O["orphan"] --> M["the map"]

One liberty in the drawing: assess is not a gate the workers wait at — it races the pool, and both widening and deepening land mid-flight.

What the agents cannot do

Agentic where the answer is a judgement, code where the answer is a guarantee:

guaranteeheld by
A citation exists only if its quote is a literal substring of bytes this run storedcore/src/evidence.ts — no fallback branch
A description with zero verified spans never reaches a readercore/src/judge.ts
competitor and substitute need that host's own readable page — a listicle nominates, it never convicts. adjacent, the softest placement and the most common one, carries no such barcore/src/verdict.ts
A claim that loses its evidence keeps its place and wears the refusalsame path — downgrade, never delete
An edge to a node nobody found gets droppedthe sweep refuses dangling edges
Every paid call lands on the run's live meter, and a watchdog ends the run just under its cap — the swarm's ledger goes further, reserving each mission's allowance before work startscore/src/spend-cap.ts

A model having a bad day writes a weak query or misreads a host. It cannot fabricate a citation or blind a market.

The second engine: the swarm

The sweep buys breadth in one pass; the swarm buys depth. A lead agent writes missions onto a priced board, six lanes claim and work them with search and page tools, and every mission reserves its allowance before any work starts. A finish the scorecard objects to comes back refused — work clears a refusal, restating the objection does not.

pnpm swarm yourcompany.com 5                          # depth, with a ceiling
pnpm swarm yourcompany.com 5 --from-sweep runs/<run>  # interrogate a sweep's map

ARCHITECTURE.md covers both engines phase by phase; DEPLOY.md covers putting it on a host.

Every command

set -a && source .env && set +a   # the CLI reads keys from the shell

pnpm sweep yourcompany.com        # breadth: the map
pnpm sweep yourcompany.com --quick  # a bounded first look: seals the search early, no paid link pass
pnpm swarm yourcompany.com 5      # depth, with a ceiling
pnpm run export <run> vault  # the map as a folder of markdown
pnpm run diff a.json b.json  # what moved between two runs of one anchor
pnpm run audit <run>         # deal a review packet, score it symmetrically
pnpm test                    # the full suite, offline, no network, no keys
pnpm check                   # CI's gate: three guards, tsc, five test projects

cd packages/web && pnpm dev  # the app, http://localhost:3210

Drive it from your coding agent

An Agent Skill at skills/mapping-markets teaches Claude Code and other agents to run maps, read them, and tune the query doctrine:

npx skills add mo-root/open-kb/skills/mapping-markets

Layout

open-kb/
├── packages/
│   ├── core/        pure logic: evidence mint, query families, span accounting
│   ├── providers/   Bright Data SERP + Unlocker, OpenRouter wiring
│   ├── sweep/       the breadth engine, one file
│   ├── swarm/       the depth engine: a lead, a funded board, six lanes
│   └── web/         Next.js: live run surface and the map
├── prompts/         every judgement, as editable markdown
└── skills/          the Agent Skill

Stack

Bright Data (SERP API, Web Unlocker) for searches that do not get blocked · OpenRouter via AI SDK 7, answers typed with Zod · Next.js 16 for the app · Supabase optional locally, required on Vercel.

License

MIT. Use it, fork it, ship it.

Built on Bright Data's web infrastructure. Not affiliated with, endorsed by, or sponsored by Bright Data.

Contributors

mo-root

237 commits

claude

86 commits

mo-root/open-kb

Plug in one domain. Get a full market map and a knowledge graph that plugs straight into your agent. Agents search the job instead of the brand name, read every host's own page, and cite it.

11

stars

323

commits

TypeScript

primary language

Sep 10, 2026

updated

open-kb-demo.vercel.app
ai-agents
competitive-intelligence
go-to-market
knowledge-graph
market-intelligence
market-research
nextjs
typescript
web-scraping

README

open·knowledge base

One domain in, knowledge base out

License: MIT Node.js >=20

→ Try the beta

Point it at your domain and it maps the whole market — competitors, substitutes, integrations, buyers, and where the market argues. It never searches the company's name: it works out the job each product does and searches for the job. Every claim carries a URL and a literal quote from a page the run fetched, and the map exports as a folder of markdown your agent can walk, with llms.txt at the door.

The launch film: twenty known domains stream past, yourcompany.com snaps into place, its glyphs detonate into de-branded queries, settle into a rotating market orbit, crystallize into a labeled knowledge graph, and plug into an agent — one domain in, knowledge base out

The launch film — watch it with sound

Quickstart

Node 20+, a Bright Data account with a SERP and an Unlocker zone, and an OpenRouter key.

git clone https://github.com/mo-root/open-kb.git && cd open-kb && pnpm install
cp .env.example .env      # four keys, named in the file
pnpm sweep yourcompany.com
runs/sweep-yourcompany-com-<stamp>.json   every entity, edge and span

runs/exports/kb-yourcompany-com/          pnpm run export <run>
├── entities/     one file per company, with its quotes
├── relations/    one file per relation found: adjacent, competitor, substitute …
├── segments/     each market, and who is in it
└── llms.txt      the door an agent comes in through

Why those two accounts. Bright Data because a map is only as good as what comes back: across the 17 sweeps in runs/, 11–15% of hosts stayed unreadable after a direct fetch and one Web Unlocker escalation, and those stay on the map wearing the reason rather than vanishing from it. OpenRouter because the judgement does not need a frontier model: in the bake-off — five configs, one company, ten queries each — the DeepSeek flash default came in cheapest per entity at $0.00065, against $0.0008 for the next best and $0.002 for the dearest config that beat it on volume. Two configs did find roughly 2.4x more entities for 3.5x and 7.7x the money; the default wins on cost per entity and on the recall probe, at the same description grounding. That is why the cheap model is the default and the spend caps are sized for it — not a claim that it finds the most.

The agents

One judgement each, every answer in a schema. Each is a markdown prompt in prompts/ — changing how the engine thinks is a text edit. Six run on every sweep:

agentownsruns
understandwhat the company sells, and which products share a marketonce per run
cataloga product's de-branded queries — the job, never the nameonce per product
assesswiden, deepen or stop, racing the searchup to eight times
classifywhat a host is, with its page in handonce per host on the default path
linkhow two entities relate40 pairs a call
orphana relation for an entity no pair reached20 at a time

Three more run BY DEFAULT since 2026-08-22 — each survived an A/B on a stored run and each has an opt-OUT environment variable: listicle-harvest mines the vendor names a roundup already printed (OPENKB_LISTICLE_HARVEST=0 turns it off — found Windsurf, Zed, Tabnine, Codeium, Aider and Continue on cursor.com with zero direct SERP hits, and 18 real vendors on grundfos.com); triage skips hosts from search metadata before a fetch is spent (OPENKB_TRIAGE=0 — 4.6% of hosts skipped, pooled over the 28 runs that record it, 1,283 of 28,182; per-market it ranges 0.3% to 13.3%); second-look re-asks classify itself against a deeper page for hosts left unknown (OPENKB_SECOND_LOOK=0 — 716 asked and 324 rescued over those same runs; a third of the asks never get a page at all). Two more stay opt-in, one environment variable each: discover and group replace the single understand call (OPENKB_DISCOVERY=agent); drop-confirm gives every settled none a second batched opinion (OPENKB_DROP_CONFIRM=1) — its own A/B did not survive, rescuing 0 of 12, 0 of 27 and 5 of 29 across three runs.

flowchart TD
    D[domain] --> U["understand<br/>reads the site"]
    U --> C["catalog<br/>per product, in parallel"]
    C --> Q["query queue"]
    Q --> W["SERP worker pool<br/><i>every hit tagged with its query</i>"]
    W --> A{"assess"}
    A -->|"widen: more queries"| Q
    A -->|"deepen: 2 pages to 4"| Q
    A -->|"enough"| H["listicle-harvest<br/><i>default on</i>"]
    H --> T["triage<br/><i>default on — skip before fetching</i>"]
    T --> K["classify<br/>page in hand"]
    K --> S["second-look · drop-confirm<br/><i>second-look default on · drop-confirm opt-in</i>"]
    S --> L["link"] --> O["orphan"] --> M["the map"]

One liberty in the drawing: assess is not a gate the workers wait at — it races the pool, and both widening and deepening land mid-flight.

What the agents cannot do

Agentic where the answer is a judgement, code where the answer is a guarantee:

guaranteeheld by
A citation exists only if its quote is a literal substring of bytes this run storedcore/src/evidence.ts — no fallback branch
A description with zero verified spans never reaches a readercore/src/judge.ts
competitor and substitute need that host's own readable page — a listicle nominates, it never convicts. adjacent, the softest placement and the most common one, carries no such barcore/src/verdict.ts
A claim that loses its evidence keeps its place and wears the refusalsame path — downgrade, never delete
An edge to a node nobody found gets droppedthe sweep refuses dangling edges
Every paid call lands on the run's live meter, and a watchdog ends the run just under its cap — the swarm's ledger goes further, reserving each mission's allowance before work startscore/src/spend-cap.ts

A model having a bad day writes a weak query or misreads a host. It cannot fabricate a citation or blind a market.

The second engine: the swarm

The sweep buys breadth in one pass; the swarm buys depth. A lead agent writes missions onto a priced board, six lanes claim and work them with search and page tools, and every mission reserves its allowance before any work starts. A finish the scorecard objects to comes back refused — work clears a refusal, restating the objection does not.

pnpm swarm yourcompany.com 5                          # depth, with a ceiling
pnpm swarm yourcompany.com 5 --from-sweep runs/<run>  # interrogate a sweep's map

ARCHITECTURE.md covers both engines phase by phase; DEPLOY.md covers putting it on a host.

Every command

set -a && source .env && set +a   # the CLI reads keys from the shell

pnpm sweep yourcompany.com        # breadth: the map
pnpm sweep yourcompany.com --quick  # a bounded first look: seals the search early, no paid link pass
pnpm swarm yourcompany.com 5      # depth, with a ceiling
pnpm run export <run> vault  # the map as a folder of markdown
pnpm run diff a.json b.json  # what moved between two runs of one anchor
pnpm run audit <run>         # deal a review packet, score it symmetrically
pnpm test                    # the full suite, offline, no network, no keys
pnpm check                   # CI's gate: three guards, tsc, five test projects

cd packages/web && pnpm dev  # the app, http://localhost:3210

Drive it from your coding agent

An Agent Skill at skills/mapping-markets teaches Claude Code and other agents to run maps, read them, and tune the query doctrine:

npx skills add mo-root/open-kb/skills/mapping-markets

Layout

open-kb/
├── packages/
│   ├── core/        pure logic: evidence mint, query families, span accounting
│   ├── providers/   Bright Data SERP + Unlocker, OpenRouter wiring
│   ├── sweep/       the breadth engine, one file
│   ├── swarm/       the depth engine: a lead, a funded board, six lanes
│   └── web/         Next.js: live run surface and the map
├── prompts/         every judgement, as editable markdown
└── skills/          the Agent Skill

Stack

Bright Data (SERP API, Web Unlocker) for searches that do not get blocked · OpenRouter via AI SDK 7, answers typed with Zod · Next.js 16 for the app · Supabase optional locally, required on Vercel.

License

MIT. Use it, fork it, ship it.

Built on Bright Data's web infrastructure. Not affiliated with, endorsed by, or sponsored by Bright Data.

Contributors

mo-root

237 commits

claude

86 commits

Languages

TypeScript

97.0%

HTML

1.6%