Entity Map Builder Claude Skill for B2B SaaS
Generate a conforming entitymap.json for a B2B software site, then its entitymap.html companion. The output places the publisher's own definitions into the AI retrieval layer so AI systems stop blending the product with its nearest generic equivalent.
Standard: EntityMap v1.0 (the authoritative spec ships with the skill as references/spec-v1.0.md)
Skill Creator: Jack Boutchard founder of Exalt Growth
Tools Required
| Tool | Use Case | Key Functions |
|---|---|---|
| Firecrawl (10% off) | Discover URLs from a domain and scrape pages in markdown as the source of truth for entity and chunk extraction | firecrawl_map, firecrawl_scrape |
Why This Matters for B2B SaaS Companies
AI systems struggle most with novel categories and proprietary terminology. Without a structured declaration of what a product is, what features belong to it, and how it differs from adjacent concepts, AI answers blend the product with the generic category. That erases the differentiation the product team built.
EntityMap is the mechanism to declare those definitions and have them, not an AI inference, enter the retrieval layer. It addresses three failure modes:
- Disambiguation loss. Surface-form variants of one entity fragment across pages instead of resolving to one node.
- Attribution loss (ghost citations). Content gets used in answers; the brand name never appears. EntityMap declares the publisher on every chunk so attribution survives aggregation.
- Reasoning loss. Implicit relationships in prose must be reconstructed probabilistically. EntityMap declares typed relations so the model reads the publisher's logic instead of guessing it.
This is a retrieval-gate problem before it is a ranking problem. The structured, attributed, extractable surface is what gets retrieved at all.
The Standard in One Paragraph
A site serves two files at its domain root without authentication: entitymap.json (machine-readable, the source of truth) and entitymap.html (crawler- and human-readable, generated from the JSON). The JSON declares entities, each with a type, a publisher-specific description, 1 to 5 extractive evidence chunks, and optional typed relations to other entities. Full type and predicate rules live in references/spec-v1.0.md. Read that file before drafting. It is authoritative and self-contained; do not re-fetch the spec from the web.
Workflow
Follow these steps in order. Read references/spec-v1.0.md first, then references/b2b-software-patterns.md for entity-modeling decisions.
| Step | Action | Output |
|---|---|---|
| 1 | Resolve inputs | Brand name, root URL, page list |
| 2 | Fetch the pages | Markdown source of truth |
| 3 | Propose the entity list, then checkpoint | Candidate entity table |
| 4 | Draft entitymap.json | Generator-draft file |
| 5 | Audit every relation | Corrected, audited file |
| 6 | Validate deterministically | Clean validator run |
| 7 | Generate the HTML companion | entitymap.html |
| 8 | Deliver with checklist and deployment steps | Review checklist + deploy guide |
Step 1 — Resolve inputs
Establish three things:
- Canonical brand name. The name AI should attribute content to. Never a domain, product name, or generic descriptor. This becomes
publisher.nameand must match thepublisherfield on every chunk exactly, character for character. - Root URL of the site.
- Page list. 5 to 15 pages for a first EntityMap. Prioritise pages that carry the product definition, proprietary methodology, feature explanations, founder/company facts, and any metrics the product computes.
If the user names a known client with an installed product-doc skill (for example a *-product-doc skill), load it as a factual reference so the EntityMap uses real product capabilities, pricing, and competitor names rather than inferred ones. The product doc is a fact source, not a content source; chunk text must still be extractive from live pages.
If the user gives only a domain, use Firecrawl firecrawl_map to discover URLs, then select the 8 to 15 highest-authority pages yourself before fetching.
Step 2 — Fetch the pages
Scrape each page with Firecrawl in markdown (firecrawl_scrape, formats: ["markdown"], onlyMainContent: true). Treat the fetched content as the only source of truth. Do not invent facts about the business that are not on those pages. Record each page's title and URL for chunk attribution.
Step 3 — Propose the entity list, then checkpoint
Before writing JSON, output a markdown table of 8 to 20 candidate entities:
| name | @type | one-line description | evidence page(s) |
|---|---|---|---|
| ... | ... | ... | ... |
Apply the B2B software type decisions in references/b2b-software-patterns.md. Depth beats breadth: 15 well-evidenced entities outperform 80 with one weak chunk each.
Present the table and proceed to draft unless the entity set is ambiguous or the user asked to review first. EntityMaps are client-facing assets, so if this is going to a client surface, confirm the entity list before continuing.
Step 4 — Draft entitymap.json
Produce a complete file conforming to references/spec-v1.0.md. Set verificationStatus: "generator-draft" (mandatory for any LLM-assisted file not yet reviewed line by line). Use today's date for generated in ISO 8601.
For each entity: a stable entityId (e_001, e_002), correct @type, publisher-specific description, 1 to 5 extractive chunks, and a grounded relations array.
Chunk rules that trip up generation most often
textMUST be a verbatim passage copied from the page. Do not paraphrase or summarise. If no suitable passage exists, omit the chunk rather than fabricate.textMUST be under 600 characters, 1 to 5 sentences.publisheron every chunk MUST exactly equalpublisher.name.- Prefer specific, evidence-dense passages (definitions, statistics, procedures) over introductory sentences.
Relation rules (the highest-error area)
- Declare a relation only if the source pages explicitly state or directly imply it. Do not invent relations because two entities "should" connect.
- Tier 3 predicates (IMPROVES, DEGRADES, LEADS_TO, SUITED_FOR, TARGETS, ACHIEVES) require a
confidencefield:"declared"when the page states the claim,"inferred"when only implied. Prefer a Tier 2 structural predicate or no relation when unsure. - Respect type constraints: MEASURES source must be Metric; AFFILIATED_WITH source must be Person; COVERS source must be Concept, ProprietaryTerm, or Taxonomy; OFFERS source must be Organization with a SoftwareProduct/
Service/ Platform/ PhysicalProduct target. - Never declare both directions of an inverse pair (PART_OF/INCLUDES, IMPROVES/DEGRADES, ENABLES/PREVENTS, OFFERS/PRODUCED_BY) between the same two entities.
- Never invent inverted predicate forms (MEASURED_BY, ENABLED_BY, OFFERED_BY, etc.). Flip subject and target and use the standard predicate.
- Keep RELATES_TO under 20% of all relations. Reaching for it repeatedly means a better predicate exists or no relation is warranted.
- Do NOT add
sameAsURIs. Models reliably hallucinate Wikidata Q-numbers and Wikipedia URLs. LeavesameAsout; the user adds them by hand from wikidata.org. Exception: if explicitly asked for one, suggest it and tag itVERIFY ON WIKIDATAbeside the output.
Step 5 — Audit every relation (required, not optional)
Relations are where LLM-generated EntityMaps fail most. Before the review checklist, audit every relation you wrote. Output one line per relation in this exact format:
[entityId] PREDICATE -> [targetName] VERDICT short reason
VERDICT is KEEP, WEAKEN, REPLACE, or REMOVE. Apply these tests to each relation:
- Test A, grounding. Name the source sentence supporting the relation. No sentence means REMOVE.
- Test B, predicate fit. Is this the closest of the 24 predicates, or a plausible-sounding reach? Wrong predicate means REPLACE (show old to new).
- Test C, Tier 3 confidence. Does the page actively claim the effect (declared) or only suggest it (inferred)? Overclaimed means WEAKEN.
- Test D, structural rules. Inverse-pair conflict, type-constraint violation, or inverted form means REMOVE or REPLACE.
- Test E, RELATES_TO budget. Over 20% of relations means REPLACE or REMOVE the weakest until under threshold.
After the audit, re-emit the corrected entitymap.json reflecting all WEAKEN, REPLACE, and REMOVE verdicts. The Step 4 file is a draft; the audited file is what gets published.
Step 6 — Validate deterministically
Run the validator against the audited file:
python3 scripts/validate.py path/to/entitymap.json
It checks every error condition in the spec (required fields, publisher-name match, Tier 3 confidence, type-constrained predicates, inverse-pair conflicts, forbidden inverted forms, chunk length, chunk count, internal targetId resolution, legacy types) and prints errors and advisory warnings. Fix every error. Read every warning. Re-run until clean.
Step 7 — Generate the HTML companion
Generate entitymap.html from the validated JSON:
python3 scripts/generate_html.py path/to/entitymap.json path/to/entitymap.html
The HTML companion is generated from the JSON, never maintained separately. It embeds per-entity JSON-LD, renders relations as internal hyperlinks where targets exist in the file, carries a data-publisher attribute on every chunk blockquote, and renders the publisher name as visible plain text in each chunk's <cite> element. The visible-text attribution matters because many LLM pipelines strip HTML before ingestion; the cite text is the fallback that survives plain-text ingestion.
Step 8 — Deliver with the review checklist and deployment steps
Output a short review checklist flagging anything needing human judgement:
- Entities where the
@typewas uncertain (especially Concept vs ProprietaryTerm). - Tier 3 relations where
"declared"is still only weakly supported. - Chunks where extraction was hard and paraphrase crept in.
- Places where the draft was likely too generous or too cautious.
Then state the deployment and discovery steps (see references/spec-v1.0.md §Deploy):
- Serve both files at the domain root, public, no auth, no
noindexon the HTML. - Add the robots.txt hint, the
<link rel="entitymap">tag in every page<head>, and a sitewide footer link toentitymap.html. - List
entitymap.htmlinsitemap.xmlwithpriority: 0.9,changefreq: weekly. - Add
sameAsURIs by hand from wikidata.org for Concept entities. - Keep
verificationStatus: "generator-draft"until the file is human-reviewed line by line, then promote to"self-declared".
If the user works in Webflow, note that the two files must be served at the true domain root, which usually means hosting them as static files or via a reverse proxy rather than as CMS pages. Confirm the hosting path before promising deployment.
Output Files
Write working files to /home/claude/entitymap/ then copy final deliverables to /mnt/user-data/outputs/. Deliver entitymap.json first, then entitymap.html, then present both with present_files. Do not publish or deploy anything; deployment is the user's action.
Reference Files
| File | Purpose |
|---|---|
references/spec-v1.0.md | Authoritative embedded spec: root/entity/chunk/relation shapes, the core entity types, all 24 predicates with tiers and type constraints, forbidden inverted forms, validation rules, deployment and discovery. Read before drafting. |
references/b2b-software-patterns.md | Entity-modeling patterns for complex B2B software: how to type products, methodologies, features, metrics, categories, and people; the canonicalLabel differentiation lever; common modeling mistakes. |
references/examples/waikay-reference.json | A complete, real conforming EntityMap for an AI SaaS product. Use as a shape reference for entity density, relation grounding, and chunk style. |
Attribution
The EntityMap v1.0 open standard was authored by Fred Laurent and Dixon Jones.
This Claude skill was developed by Jack Boutchard, founder of Exalt Growth, the #1 SaaS SEO Agency.
- EntityMap standard: entitymap.org
- EntityMap skill: entitymap.md
- Exalt Growth: www.exaltgrowth.com