Skip to content

[WIP] Initial docs for ENSDb#1942

Draft
tk-o wants to merge 3 commits intomainfrom
docs/ensdb
Draft

[WIP] Initial docs for ENSDb#1942
tk-o wants to merge 3 commits intomainfrom
docs/ensdb

Conversation

@tk-o
Copy link
Copy Markdown
Member

@tk-o tk-o commented Apr 16, 2026

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • Please consider it still being work in progress. Many more refinements to be applied.

Why

  • Why this change exists. Link to related GitHub issues where relevant.

Testing

  • How this was tested.
  • If you didn't test it, say why.

Notes for Reviewer (Optional)

  • Anything non-obvious or worth a heads-up.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Please consider it still being work in progress. Many more refinements to be applied.
Copilot AI review requested due to automatic review settings April 16, 2026 15:52
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 16, 2026

⚠️ No Changeset found

Latest commit: d9b125d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ensnode.io Ready Ready Preview, Comment Apr 17, 2026 6:53am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped Apr 17, 2026 6:53am
ensrainbow.io Skipped Skipped Apr 17, 2026 6:53am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

Warning

Rate limit exceeded

@tk-o has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 7 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 12 minutes and 7 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fc04f302-bf3c-4cce-a05b-dc30d7345225

📥 Commits

Reviewing files that changed from the base of the PR and between 3a8c453 and d9b125d.

📒 Files selected for processing (12)
  • docs/ensnode.io/config/integrations/starlight.ts
  • docs/ensnode.io/src/content/docs/ensdb/concepts/architecture.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/faq.mdx
  • docs/ensnode.io/src/content/docs/ensdb/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/integrations/ensnode.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/sdk.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/sql.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/troubleshooting.mdx
📝 Walkthrough

Walkthrough

ENSDb documentation transitions from "Coming soon" status to comprehensive "Getting started" content, including concepts, glossaries, architecture diagrams, and quick-start guides. Supporting configuration files for Letta AI integration are added, along with CSS styling updates.

Changes

Cohort / File(s) Summary
Documentation Configuration
docs/ensnode.io/config/integrations/starlight.ts
Updated sidebar topics for ENSDb: renamed "Overview" label from "Coming soon" to "Getting started", and added "Concepts", "Usage", and "Use Cases" sections (expanded) plus "Integrations" and "Operations" (collapsed) with autogenerate directories.
ENSDb Core Documentation
docs/ensnode.io/src/content/docs/ensdb/index.mdx, docs/ensnode.io/src/content/docs/ensdb/concepts/index.mdx, docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx
Expanded main ENSDb page from "WIP" placeholder to complete "Getting started" guide with quick-start, architecture diagrams, and reference materials. Added "Concepts" index page and comprehensive glossary defining PostgreSQL/ENSDb terminology, schema concepts, runtime processes, and indexing behavior.
Architecture Documentation
docs/ensnode.io/mindmap.md
New Mermaid mindmap diagram documenting ENSDb architecture, including Vision, Foundations, Operations, Tools, and Integrations sections with infrastructure and SDK details.
Styling Updates
docs/ensnode.io/src/styles/starlight.css
Refined CSS selectors by removing descendant spaces for more precise matching, adjusted markdown list styling with inside positioning and nested margins, and normalized selector formatting.
Letta AI Configuration
.letta/.lettaignore, .letta/settings.json, .letta/settings.local.json
Added Letta exclusion patterns for build/dependency directories, permission rules for documentation file editing, and local session state configuration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 The docs now shine where once was gray,
From "coming soon" to "start today!"
A glossary hops, concepts leap high,
Architecture mindmaps fill the sky. 🌳✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses the required template structure but leaves critical sections largely empty, with placeholders for 'Why', 'Testing', and 'Notes for Reviewer' containing only instructional text without actual content. Complete the 'Why' section with rationale and related GitHub issues, fill 'Testing' with testing details or explanation, and add any relevant reviewer notes. Also address the blocking checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title '[WIP] Initial docs for ENSDb' accurately reflects the main change: adding initial documentation for ENSDb. It is clear, concise, and directly related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/ensdb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/ensnode.io/mindmap.md`:
- Line 1: The file violates markdownlint MD041 because it begins with a code
fence (```mermaid) instead of an H1; add a top-level heading above the existing
mermaid block (e.g., a single line starting with "# " with an appropriate title)
so the document starts with an H1, keeping the existing ```mermaid ... mindmap
... ``` block unchanged below it.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/architecture.mdx`:
- Line 281: The link text "**[Schema
Version](/ensdb/concepts/glossary#schema-version) evolution**" points to a
non-existent anchor "#schema-version"; either update the link to the correct
anchor name used in the glossary (e.g., match the actual heading ID) or add the
corresponding "Schema Version" heading/anchor to the glossary so
"/ensdb/concepts/glossary#schema-version" resolves; locate the link in the
architecture.mdx content and fix the anchor target or glossary heading to make
the anchor valid.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx`:
- Line 905: The doc text references the camelCase column name `labelName` but
the schema uses snake_case `label_name`; update the documentation sentence that
mentions `labelName` to use the exact `label_name` identifier so the column name
matches the table definition and avoids SQL copy/paste errors (ensure any other
occurrences of `labelName` in this file are replaced with `label_name` for
consistency with the table schema).
- Around line 1142-1146: The table rows mapping domain tables to the
registrations table are pointing to the wrong sub-schema ("registrars"); update
the two rows where From Sub-Schema is "ensv2" and Table is "v1_domains" and
"v2_domains" to set the To Sub-Schema to "ensv2" (so the To Table
"registrations" correctly belongs to the ensv2 sub-schema), leaving the rest of
the row (Relationship and Via) unchanged.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx`:
- Around line 146-158: The glossary currently lists a non-existent key
`indexing_metadata_context`; update the table and section to match the actual
implementation in the EnsNodeMetadataKeys enum by replacing that single row with
three rows for the real keys: `ensdb_version`, `ensindexer_public_config`, and
`ensindexer_indexing_status`. Adjust the "Indexing Metadata Context" section
(rename if appropriate) to document each of those three keys individually,
describing their JSON/value shape and how they map to the ENSNode stack (e.g.,
`ensdb_version` = version string for the metadata structure,
`ensindexer_public_config` = public config for the ENSIndexer instance,
`ensindexer_indexing_status` = current indexing status object), and ensure
references to ENSIndexer/ENSDb/ENSRainbow match the writer docs and the
EnsNodeMetadataKeys enum in packages/ensdb-sdk/src/client/ensnode-metadata.ts.

In `@docs/ensnode.io/src/content/docs/ensdb/index.mdx`:
- Around line 41-43: The Mermaid graph incorrectly labels the mainnet API node;
update the label for the ENSApiMainnet node (adjacent to ENSIndexerMainnet) from
"ENSApi Sepolia instances" to a mainnet-appropriate label such as "ENSApi
Mainnet instances" so the node context matches the surrounding mainnet entries.
- Around line 209-215: The SDK snippet has a duplicated .limit(10) call and uses
the wrong schema member name; update the query built from EnsDbReader so it
calls .from(ensDbReader.ensIndexerSchema.v1_domains) (not v1Domain) and remove
the extra .limit(10) so the chain ends with a single .limit(10); ensure the call
chain on ensDbReader.ensDb.select().from(...).limit(10) is syntactically valid
with proper semicolons and line breaks.

In `@docs/ensnode.io/src/content/docs/ensdb/integrations/index.mdx`:
- Line 155: The label ENSDb["ENSDb<br/>(SQLite)"] is inconsistent with the
PostgreSQL model used elsewhere; update the label to match the PostgreSQL
variant (e.g., ENSDb["ENSDb<br/>(PostgreSQL)"] or simply ENSDb["ENSDb"]) so it
aligns with surrounding docs and avoids confusion—locate and edit the
ENSDb["ENSDb<br/>(SQLite)"] entry to the correct PostgreSQL label in the
integrations content.
- Around line 191-197: The diagram currently has Writer pointing to
ReaderGraphQL/ReaderAnalytics/ReaderCLI; change the flow so Writer writes to
ENSDb and each reader queries ENSDb. Replace the three lines "Writer -->
ReaderGraphQL/ReaderAnalytics/ReaderCLI" with a single or three lines "Writer
--> ENSDb" and ensure the reader edges remain or are expressed as "ReaderGraphQL
--> ENSDb", "ReaderAnalytics --> ENSDb", "ReaderCLI --> ENSDb" so the Writer ->
ENSDb and Reader* -> ENSDb directions are correct.

In `@docs/ensnode.io/src/content/docs/ensdb/integrations/reader.mdx`:
- Around line 320-327: The SQL example ends the triple-quoted string incorrectly
with two quotes; update the cursor.execute call (cursor.execute) so the SQL TEXT
block is properly closed with triple quotes (""") and keep the parameters tuple
unchanged; ensure the block reads SELECT ... LIMIT 100 inside a properly started
and terminated triple-quoted string to produce valid Python.

In `@docs/ensnode.io/src/content/docs/ensdb/integrations/writer.mdx`:
- Around line 337-340: The SQL snippet creates an index non-idempotently: change
the CREATE INDEX v1_domains_by_owner ON
ensindexer_mycustom.v1_domains(owner_id); statement to use the idempotent form
supported by PostgreSQL by adding IF NOT EXISTS so repeated runs don’t error;
update the example that references the index name v1_domains_by_owner and the
table ensindexer_mycustom.v1_domains accordingly in the writer.mdx docs.
- Around line 202-237: The three INSERT statements into the ensnode.metadata
table (the ones inserting keys 'ensdb_version', 'ensindexer_public_config', and
'ensindexer_indexing_status') must be made idempotent by adding an ON CONFLICT
clause on the composite primary key (ens_indexer_schema_name, key); update the
statements for the INSERTs that create these rows so they include ON CONFLICT
(ens_indexer_schema_name, key) DO UPDATE SET value = EXCLUDED.value,
value_version = EXCLUDED.value_version (or DO NOTHING if you prefer to keep
existing values), and apply the same pattern to the other two INSERTs so
rerunning the script won’t error on duplicate key violations.
- Around line 246-285: The snippet in Step 6 uses pool.query(...) but doesn't
define pool locally, so make the snippet self-contained by adding a pool
definition (e.g., create a new PG client Pool instance and import it) before its
use; ensure you import Pool from 'pg' (or reference the same pool variable you
defined earlier) and initialize it with the connection env var (e.g.,
process.env.PG_CONNECTION_STRING) so that pool.query in the loop works when the
snippet is copied in isolation.

In `@docs/ensnode.io/src/content/docs/ensdb/operations/index.mdx`:
- Around line 240-243: The metric's SQL uses an invalid call
pg_total_relation_size('ponder_sync.*'); replace it with a query that sums
pg_total_relation_size over all tables in the ponder_sync schema (e.g., select
sum of pg_total_relation_size(...) for tables where schemaname = 'ponder_sync'),
casting each table identifier to regclass (use format('%I.%I', schemaname,
tablename)::regclass) so pg_total_relation_size can accept each table; update
the Ponder Schema size metric to use this aggregated query and present the total
size (optionally formatted with pg_size_pretty) instead of the wildcard
argument.
- Around line 314-323: The Card components inside CardGrid (the entries titled
"Database Schemas", "Architecture", and "ENS Namespaces") are non-navigable and
should be replaced with Starlight's LinkCard so they become actionable; update
the JSX to use LinkCard for those three items (e.g., replace Card elements
referencing the titles "Database Schemas", "Architecture", "ENS Namespaces" with
LinkCard) and add the import for LinkCard from '@astrojs/starlight/components'
at the top of the file, and for the "ENS Namespaces" LinkCard either point it to
an existing documentation path or remove that LinkCard/create the missing doc if
no path exists.

In `@docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx`:
- Line 27: Update the description string that currently reads
description="TypeScript utilities for typing-safe ENSDb access" to use the
correct phrase "type-safe" instead of "typing-safe"; locate the description
attribute in the frontmatter or metadata block and replace "typing-safe" with
"type-safe" so it reads description="TypeScript utilities for type-safe ENSDb
access".
- Around line 66-87: The example mixes CommonJS require('pg') with top-level
await (pool.query), which is invalid; fix by either converting the module to an
ES module (use import { Pool } from 'pg' and ensure the file is an ESM so
top-level await is allowed) or keep CommonJS and wrap the awaits in an async
IIFE (e.g., create an async function that creates const pool = new Pool(...) and
calls await pool.query(...)); update references to Pool, pool, and pool.query
accordingly so the example is syntactically correct for the chosen module
system.

In `@docs/ensnode.io/src/content/docs/ensdb/usage/querying.mdx`:
- Around line 155-159: The SQL example uses a malformed hex literal in the WHERE
clause; update the literal in the query that selects from
ensindexer_mainnet.labels (columns label_hash, interpreted) by removing the
underscore after the \x escape so the hex literal becomes '\xaf2caa...03cc'
instead of '\x_af2caa...03cc'.

In `@docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx`:
- Line 73: The WHERE clause uses an invalid bytea literal '\x0x...'; replace it
with valid PostgreSQL bytea syntax such as the hex format '\\x0x...'
(double-escaped backslash in source) or use decode('0x...', 'hex') for
comparisons; update the selector comparison in the query (the WHERE e.selector =
'...') to use either e.selector = '\\x0x...' or e.selector = decode('0x...',
'hex') so PostgreSQL accepts the bytea literal.
- Around line 305-307: The snippet incorrectly treats asyncpg.add_listener as an
async context manager; replace that pattern by registering a callback via
conn.add_listener(channel, callback) where callback(connection, pid, channel,
payload) handles the event (or enqueues it into an asyncio.Queue if you need an
async consumer), and unregister with conn.remove_listener(channel, callback)
when done; update any code that assumed "async with
conn.add_listener('ens_events') as queue" to define a listener function and call
conn.add_listener('ens_events', listener) instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 267b8045-48ef-43d5-941e-841f36cdd703

📥 Commits

Reviewing files that changed from the base of the PR and between b8f5be7 and 00befeb.

📒 Files selected for processing (19)
  • docs/ensnode.io/config/integrations/starlight.ts
  • docs/ensnode.io/mindmap.md
  • docs/ensnode.io/src/content/docs/ensdb/concepts/architecture.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/concepts/indexing-lifecycle.mdx
  • docs/ensnode.io/src/content/docs/ensdb/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/integrations/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/integrations/reader.mdx
  • docs/ensnode.io/src/content/docs/ensdb/integrations/writer.mdx
  • docs/ensnode.io/src/content/docs/ensdb/operations/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/reader.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/writer.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx
  • docs/ensnode.io/src/content/docs/ensdb/usage/querying.mdx
  • docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx
  • docs/ensnode.io/src/styles/starlight.css

@@ -0,0 +1,80 @@
```mermaid
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.

⚠️ Potential issue | 🟡 Minor

Add a top-level heading to satisfy markdownlint MD041.

The file starts with a code fence instead of an H1.

Suggested patch
+# ENSDb Mindmap
+
 ```mermaid
 mindmap
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```mermaid
# ENSDb Mindmap
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/mindmap.md` at line 1, The file violates markdownlint MD041
because it begins with a code fence (```mermaid) instead of an H1; add a
top-level heading above the existing mermaid block (e.g., a single line starting
with "# " with an appropriate title) so the document starts with an H1, keeping
the existing ```mermaid ... mindmap ... ``` block unchanged below it.

- **Separate indexing per chain** — mainnet, L2s, testnets as independent tenants
- **Independent operation** — one tenant can restart while others continue unaffected
- **Custom indexing** — specialized tenants for specific use cases
- **[Schema Version](/ensdb/concepts/glossary#schema-version) evolution** — different tenants can use different schema versions
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.

⚠️ Potential issue | 🟡 Minor

Fix broken glossary anchor link.

Line 281 links to #schema-version, but the glossary page in this PR does not define that anchor, so the link will not resolve.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/architecture.mdx` at line
281, The link text "**[Schema Version](/ensdb/concepts/glossary#schema-version)
evolution**" points to a non-existent anchor "#schema-version"; either update
the link to the correct anchor name used in the glossary (e.g., match the actual
heading ID) or add the corresponding "Schema Version" heading/anchor to the
glossary so "/ensdb/concepts/glossary#schema-version" resolves; locate the link
in the architecture.mdx content and fix the anchor target or glossary heading to
make the anchor valid.

- `byResolvedAddressId`: `resolved_address_id`

<Aside type="note">
String columns `name` and `labelName` use PostgreSQL collation "C" for subgraph compatibility.
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.

⚠️ Potential issue | 🟡 Minor

Use the documented snake_case column name consistently.

Line 905 references labelName, but the table definition uses label_name (Line 881). Keep this exact to avoid copy/paste errors in SQL.

Suggested doc patch
-String columns `name` and `labelName` use PostgreSQL collation "C" for subgraph compatibility.
+String columns `name` and `label_name` use PostgreSQL collation "C" for subgraph compatibility.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String columns `name` and `labelName` use PostgreSQL collation "C" for subgraph compatibility.
String columns `name` and `label_name` use PostgreSQL collation "C" for subgraph compatibility.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx` at line
905, The doc text references the camelCase column name `labelName` but the
schema uses snake_case `label_name`; update the documentation sentence that
mentions `labelName` to use the exact `label_name` identifier so the column name
matches the table definition and avoids SQL copy/paste errors (ensure any other
occurrences of `labelName` in this file are replaced with `label_name` for
consistency with the table schema).

Comment on lines +1142 to +1146
| From Sub-Schema | Table | Relationship | To Sub-Schema | Table | Via |
|-----------------|-------|--------------|---------------|-------|-----|
| ensv2 | `v1_domains` | has | registrars | `registrations` | `domain_id` |
| ensv2 | `v2_domains` | has | registrars | `registrations` | `domain_id` |
| ensv2 | `v1_domains` | maps to | subgraph | `subgraph_domains` | `id` (node) |
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.

⚠️ Potential issue | 🟠 Major

Correct sub-schema mapping for registrations.

Lines 1144-1145 map registrations to registrars, but this page defines registrations under the ensv2 sub-schema. This inconsistency can lead readers to query the wrong schema.

Suggested doc patch
-| ensv2 | `v1_domains` | has | registrars | `registrations` | `domain_id` |
-| ensv2 | `v2_domains` | has | registrars | `registrations` | `domain_id` |
+| ensv2 | `v1_domains` | has | ensv2 | `registrations` | `domain_id` |
+| ensv2 | `v2_domains` | has | ensv2 | `registrations` | `domain_id` |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| From Sub-Schema | Table | Relationship | To Sub-Schema | Table | Via |
|-----------------|-------|--------------|---------------|-------|-----|
| ensv2 | `v1_domains` | has | registrars | `registrations` | `domain_id` |
| ensv2 | `v2_domains` | has | registrars | `registrations` | `domain_id` |
| ensv2 | `v1_domains` | maps to | subgraph | `subgraph_domains` | `id` (node) |
| From Sub-Schema | Table | Relationship | To Sub-Schema | Table | Via |
|-----------------|-------|--------------|---------------|-------|-----|
| ensv2 | `v1_domains` | has | ensv2 | `registrations` | `domain_id` |
| ensv2 | `v2_domains` | has | ensv2 | `registrations` | `domain_id` |
| ensv2 | `v1_domains` | maps to | subgraph | `subgraph_domains` | `id` (node) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx` around
lines 1142 - 1146, The table rows mapping domain tables to the registrations
table are pointing to the wrong sub-schema ("registrars"); update the two rows
where From Sub-Schema is "ensv2" and Table is "v1_domains" and "v2_domains" to
set the To Sub-Schema to "ensv2" (so the To Table "registrations" correctly
belongs to the ensv2 sub-schema), leaving the rest of the row (Relationship and
Via) unchanged.

Comment on lines +146 to +158
| Key | Description |
|-----|-------------|
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |

#### Indexing Metadata Context

A JSON object that provides context about the ENSNode stack the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance).
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to.
- `ensRainbowPublicConfig`: the public config of the ENSRainbow instance that this [ENSIndexer instance](#ensindexer-instance) is connected to. Might be `null` during the ENSNode stack cold start, when the ENSIndexer instance starts before the ENSRainbow instance.
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "ensdb_version|ensindexer_public_config|ensindexer_indexing_status|indexing_metadata_context" \
  docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx \
  docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/writer.mdx -C2
rg -n "EnsNodeMetadataKeys\\.(EnsDbVersion|EnsIndexerPublicConfig|EnsIndexerIndexingStatus)" \
  packages/ensdb-sdk/src/client/ensdb-writer.ts -C2

Repository: namehash/ensnode

Length of output: 3709


🏁 Script executed:

# Search for indexing_metadata_context in the entire codebase
rg -r "indexing_metadata_context" --type typescript --type mdx --type json

# Check the EnsNodeMetadataKeys enum definition
rg -n "enum EnsNodeMetadataKeys|EnsNodeMetadataKeys\s*=" packages/ensdb-sdk/src -A5

# Look at the type definitions for metadata keys
fd -e ts -e tsx packages/ensdb-sdk/src | xargs rg -l "EnsNodeMetadataKeys" | head -5

Repository: namehash/ensnode

Length of output: 1632


🏁 Script executed:

# Read the ensnode-metadata.ts file to understand the metadata structure
cat -n packages/ensdb-sdk/src/client/ensnode-metadata.ts

# Check the serialize functions to understand what the values look like
cat -n packages/ensdb-sdk/src/client/serialize/ensnode-metadata.ts

Repository: namehash/ensnode

Length of output: 3056


Update the glossary to document the actual metadata keys.

The glossary documents indexing_metadata_context as a metadata key, but it doesn't exist in the implementation. The actual EnsNodeMetadataKeys enum in packages/ensdb-sdk/src/client/ensnode-metadata.ts defines three separate keys: ensdb_version, ensindexer_public_config, and ensindexer_indexing_status—which correctly align with the writer documentation. Replace the single indexing_metadata_context row with entries for these three actual keys, and update the "Indexing Metadata Context" section accordingly to match the implementation.

🧰 Tools
🪛 LanguageTool

[style] ~154-~154: This phrase is redundant. Consider writing “evolve”.
Context: ...ctual context data, whose structure may evolve over time as the needs of the ENSNode stack evolv...

(EVOLVE_OVER_TIME)


[style] ~158-~158: To form a complete sentence, be sure to include a subject.
Context: ...(#ensindexer-instance) is connected to. Might be null during the ENSNode stack cold...

(MISSING_IT_THERE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx` around lines
146 - 158, The glossary currently lists a non-existent key
`indexing_metadata_context`; update the table and section to match the actual
implementation in the EnsNodeMetadataKeys enum by replacing that single row with
three rows for the real keys: `ensdb_version`, `ensindexer_public_config`, and
`ensindexer_indexing_status`. Adjust the "Indexing Metadata Context" section
(rename if appropriate) to document each of those three keys individually,
describing their JSON/value shape and how they map to the ENSNode stack (e.g.,
`ensdb_version` = version string for the metadata structure,
`ensindexer_public_config` = public config for the ENSIndexer instance,
`ensindexer_indexing_status` = current indexing status object), and ensure
references to ENSIndexer/ENSDb/ENSRainbow match the writer docs and the
EnsNodeMetadataKeys enum in packages/ensdb-sdk/src/client/ensnode-metadata.ts.


<LinkCard
title="ENSDb SDK"
description="TypeScript utilities for typing-safe ENSDb access"
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.

⚠️ Potential issue | 🟡 Minor

Fix typo in SDK description.

Line 27 uses “typing-safe”; this should be “type-safe.”

Suggested patch
-  description="TypeScript utilities for typing-safe ENSDb access"
+  description="TypeScript utilities for type-safe ENSDb access"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description="TypeScript utilities for typing-safe ENSDb access"
description="TypeScript utilities for type-safe ENSDb access"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx` at line 27, Update
the description string that currently reads description="TypeScript utilities
for typing-safe ENSDb access" to use the correct phrase "type-safe" instead of
"typing-safe"; locate the description attribute in the frontmatter or metadata
block and replace "typing-safe" with "type-safe" so it reads
description="TypeScript utilities for type-safe ENSDb access".

Comment on lines +66 to +87
```javascript
const { Pool } = require('pg');

const pool = new Pool({
host: 'localhost',
database: 'ensdb',
user: 'postgres',
password: 'password',
});

// Discover ENSIndexer Schemas
const { rows: schemas } = await pool.query(`
SELECT DISTINCT ens_indexer_schema_name
FROM ensnode.metadata
`);

// Query indexed data
const { rows: domains } = await pool.query(`
SELECT * FROM ensindexer_abc123.v1_domains
LIMIT 10
`);
```
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Node.js, is top-level awaitvalid in CommonJS files that userequire(...), or only in ES modules?

💡 Result:

Top-level await is valid only in ES modules (.mjs files or with "type": "module" in package.json), not in CommonJS files that use require(...).

Citations:


🏁 Script executed:

# Check if the file exists and read lines 66-87
if [ -f "docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx" ]; then
  echo "=== File exists, reading lines 66-87 ==="
  sed -n '66,87p' "docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx"
else
  echo "File not found at expected path. Searching for similar files..."
  find . -name "index.mdx" -path "*/ensdb/usage/*" 2>/dev/null | head -5
fi

Repository: namehash/ensnode

Length of output: 542


JavaScript example mixes CommonJS with top-level await, which is invalid.

Line 67 uses require(...) (CommonJS), but lines 77 and 83 use top-level await. Top-level await is only valid in ES modules, not in CommonJS files. Wrap the code in an async IIFE or convert to ES module syntax.

Suggested patch
 const { Pool } = require('pg');

-const pool = new Pool({
-  host: 'localhost',
-  database: 'ensdb',
-  user: 'postgres',
-  password: 'password',
-});
-
-// Discover ENSIndexer Schemas
-const { rows: schemas } = await pool.query(`
-  SELECT DISTINCT ens_indexer_schema_name
-  FROM ensnode.metadata
-`);
-
-// Query indexed data
-const { rows: domains } = await pool.query(`
-  SELECT * FROM ensindexer_abc123.v1_domains
-  LIMIT 10
-`);
+(async () => {
+  const pool = new Pool({
+    host: 'localhost',
+    database: 'ensdb',
+    user: 'postgres',
+    password: 'password',
+  });
+
+  // Discover ENSIndexer Schemas
+  const { rows: schemas } = await pool.query(`
+    SELECT DISTINCT ens_indexer_schema_name
+    FROM ensnode.metadata
+  `);
+
+  // Query indexed data
+  const { rows: domains } = await pool.query(`
+    SELECT * FROM ensindexer_abc123.v1_domains
+    LIMIT 10
+  `);
+})();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx` around lines 66 - 87,
The example mixes CommonJS require('pg') with top-level await (pool.query),
which is invalid; fix by either converting the module to an ES module (use
import { Pool } from 'pg' and ensure the file is an ESM so top-level await is
allowed) or keep CommonJS and wrap the awaits in an async IIFE (e.g., create an
async function that creates const pool = new Pool(...) and calls await
pool.query(...)); update references to Pool, pool, and pool.query accordingly so
the example is syntactically correct for the chosen module system.

Comment on lines +155 to +159
-- Look up interpreted label for a labelhash
SELECT label_hash, interpreted
FROM ensindexer_mainnet.labels
WHERE label_hash = '\x_af2caa...03cc';

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "\\\\x_" docs/ensnode.io/src/content/docs/ensdb/usage/querying.mdx -C2

Repository: namehash/ensnode

Length of output: 218


Correct the malformed hex literal in the SQL example.

Line 158 contains '\x_af2caa...03cc', which is invalid SQL syntax. Remove the underscore after \x to form a valid hex literal: '\xaf2caa...03cc'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/usage/querying.mdx` around lines 155 -
159, The SQL example uses a malformed hex literal in the WHERE clause; update
the literal in the query that selects from ensindexer_mainnet.labels (columns
label_hash, interpreted) by removing the underscore after the \x escape so the
hex literal becomes '\xaf2caa...03cc' instead of '\x_af2caa...03cc'.

FROM ensindexer_mainnet.events e
JOIN ensindexer_mainnet.domain_events de ON e.id = de.event_id
JOIN ensindexer_mainnet.v1_domains d ON de.domain_id = d.id
WHERE e.selector = '\x0x...' -- NewOwner event
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the correct PostgreSQL syntax for comparing a BYTEA column to hex data (e.g., using decode(..., 'hex') or \\x... literals)?

💡 Result:

The correct PostgreSQL syntax for comparing a BYTEA column (e.g., mytable.mybytea) to hex data uses either the \x hex literal or decode('hexstring', 'hex'): 1. Using hex literal (preferred, direct bytea literal): WHERE mytable.mybytea = '\xDEADBEEF'::bytea (Note: In SQL strings, escape the backslash as \x; hex digits are case-insensitive.) 2. Using decode function (for hex strings from variables or longer values): WHERE mytable.mybytea = decode('DEADBEEF', 'hex') Both produce bytea values for direct equality comparison (= operator). The hex literal is faster and recommended by official docs for literals. Examples work in PostgreSQL 9.0+ (hex format introduced then; current as of 2026 is v18). Example query: SELECT * FROM mytable WHERE mybytea = '\xdeadbeef'::bytea; Equivalent: SELECT * FROM mytable WHERE mybytea = decode('deadbeef', 'hex');

Citations:


🏁 Script executed:

fd -t f 'index.mdx' | grep -E 'ensdb/use-cases'

Repository: namehash/ensnode

Length of output: 118


🏁 Script executed:

sed -n '70,80p' docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx

Repository: namehash/ensnode

Length of output: 409


🏁 Script executed:

grep -n "\\\\x0x" docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx

Repository: namehash/ensnode

Length of output: 109


Replace malformed bytea literal with valid PostgreSQL syntax.

Line 73 uses '\x0x...', which is not valid PostgreSQL bytea syntax. PostgreSQL requires either the \\x hex literal format or the decode() function for bytea comparisons.

Suggested patch
-WHERE e.selector = '\x0x...' -- NewOwner event
+WHERE e.selector = decode('YOUR_EVENT_SELECTOR_HEX', 'hex') -- NewOwner event (no 0x prefix)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WHERE e.selector = '\x0x...' -- NewOwner event
WHERE e.selector = decode('YOUR_EVENT_SELECTOR_HEX', 'hex') -- NewOwner event (no 0x prefix)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx` at line 73, The
WHERE clause uses an invalid bytea literal '\x0x...'; replace it with valid
PostgreSQL bytea syntax such as the hex format '\\x0x...' (double-escaped
backslash in source) or use decode('0x...', 'hex') for comparisons; update the
selector comparison in the query (the WHERE e.selector = '...') to use either
e.selector = '\\x0x...' or e.selector = decode('0x...', 'hex') so PostgreSQL
accepts the bytea literal.

Comment on lines +305 to +307
async with conn.add_listener('ens_events') as queue:
async for event in queue:
# New event detected
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In asyncpg, what is the correct API pattern for LISTEN/NOTIFY subscriptions—does add_listener return a context manager/queue, or does it require a callback?

💡 Result:

In asyncpg, the correct API pattern for LISTEN/NOTIFY subscriptions is to use Connection.add_listener(channel, callback), which requires a callback function (regular callable or coroutine function since version 0.24.0). The callback receives arguments: connection, pid (sender PID), channel, and payload. It does not return a context manager or queue.

Citations:


Use callback-based API for asyncpg.add_listener()—not context manager/stream.

The code attempts to use add_listener as an async context manager that yields a queue, but asyncpg's API requires a callback function. The add_listener(channel, callback) method accepts a regular callable or coroutine function that receives (connection, pid, channel, payload) arguments.

Suggested fix
-    async with conn.add_listener('ens_events') as queue:
-        async for event in queue:
-            # New event detected
-            event_data = json.loads(event.payload)
+    async def on_event(_conn, _pid, _channel, payload):
+        # New event detected
+        event_data = json.loads(payload)
+        # process event_data...
+
+    await conn.add_listener('ens_events', on_event)
+    await asyncio.Event().wait()  # keep process alive
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx` around lines 305
- 307, The snippet incorrectly treats asyncpg.add_listener as an async context
manager; replace that pattern by registering a callback via
conn.add_listener(channel, callback) where callback(connection, pid, channel,
payload) handles the event (or enqueues it into an asyncio.Queue if you need an
async consumer), and unregister with conn.remove_listener(channel, callback)
when done; update any code that assumed "async with
conn.add_listener('ens_events') as queue" to define a listener function and call
conn.add_listener('ens_events', listener) instead.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an initial ENSDb documentation section to the ensnode.io docs site, including conceptual overviews and practical guides, and wires it into the Starlight sidebar.

Changes:

  • Introduces new ENSDb docs pages (Concepts, Usage, Integrations, Use Cases, Operations).
  • Updates the ENSDb landing page from “WIP/Coming soon” to a full “Getting started” overview.
  • Tweaks Starlight CSS for markdown list rendering and sidebar/pagination selector formatting.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
docs/ensnode.io/src/styles/starlight.css Adjusts markdown list styling and cleans up selector formatting/spacing.
docs/ensnode.io/src/content/docs/ensdb/index.mdx Replaces the ENSDb placeholder with a full getting-started overview and examples.
docs/ensnode.io/src/content/docs/ensdb/concepts/index.mdx Adds Concepts landing page with links to core conceptual docs.
docs/ensnode.io/src/content/docs/ensdb/concepts/architecture.mdx Documents ENSDb architecture (writer/reader pattern, schemas, server vs instance).
docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx Adds comprehensive schema reference and diagrams for ENSDb.
docs/ensnode.io/src/content/docs/ensdb/concepts/glossary.mdx Adds glossary of ENSDb and PostgreSQL terminology.
docs/ensnode.io/src/content/docs/ensdb/concepts/indexing-lifecycle.mdx Documents backfill/following lifecycle and index behavior.
docs/ensnode.io/src/content/docs/ensdb/usage/index.mdx Adds Usage landing page with language examples and links to querying/SDK docs.
docs/ensnode.io/src/content/docs/ensdb/usage/querying.mdx Adds SQL querying guide (schema discovery, status checks, query patterns).
docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/index.mdx Adds ENSDb SDK overview page with structure and links.
docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/reader.mdx Adds ENSDb Reader SDK reference and usage examples.
docs/ensnode.io/src/content/docs/ensdb/usage/ensdb-sdk/writer.mdx Adds ENSDb Writer SDK reference (migrations + metadata upserts).
docs/ensnode.io/src/content/docs/ensdb/integrations/index.mdx Adds integrations overview (writer/reader pattern, compliance checklist).
docs/ensnode.io/src/content/docs/ensdb/integrations/reader.mdx Adds “Build a Custom Reader” guide with multi-language examples.
docs/ensnode.io/src/content/docs/ensdb/integrations/writer.mdx Adds “Build a Custom Writer” guide with lifecycle + schema requirements.
docs/ensnode.io/src/content/docs/ensdb/use-cases/index.mdx Adds ENSDb use-cases page with example queries and patterns.
docs/ensnode.io/src/content/docs/ensdb/operations/index.mdx Adds operational guidance (multitenancy, namespace isolation, backups).
docs/ensnode.io/mindmap.md Adds a Mermaid mindmap capturing ENSDb conceptual structure.
docs/ensnode.io/config/integrations/starlight.ts Updates sidebar nav to include ENSDb Concepts/Usage/Use Cases/Integrations/Operations sections.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

|--------|------|---------|
| `ens_indexer_schema_name` | `text` | References the [ENSIndexer Schema Name](#ensindexer-schema-name) of the ENSIndexer instance that manages this metadata record |
| `key` | `text` | Type of metadata record |
| `value` | `jsonb` | The context object (configuration, status, etc.) |
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The ENSNode metadata table definition here omits the value_version column, but other docs in this PR describe ensnode.metadata as having value_version (e.g. in Database Schemas / Writer docs). Please add value_version to this glossary table (or clarify if the glossary is describing a different/older schema).

Suggested change
| `value` | `jsonb` | The context object (configuration, status, etc.) |
| `value` | `jsonb` | The context object (configuration, status, etc.) |
| `value_version` | `integer` | Version of the structure stored in `value` |

Copilot uses AI. Check for mistakes.
subgraph ENSNodeMainnet["ENSNode 'Mainnet' instance"]
direction LR
ENSIndexerMainnet[ENSIndexer 'Mainnet' instance]
ENSApiMainnet@{ shape: procs, label: "ENSApi Sepolia instances" }
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The Mermaid diagram node ENSApiMainnet is labeled as “ENSApi Sepolia instances”, which is confusing/misleading in the Mainnet subgraph. Update the label to reflect mainnet (or rename the node) so the diagram matches the surrounding headings.

Suggested change
ENSApiMainnet@{ shape: procs, label: "ENSApi Sepolia instances" }
ENSApiMainnet@{ shape: procs, label: "ENSApi Mainnet instance" }

Copilot uses AI. Check for mistakes.
Comment on lines +212 to +214
.from(ensDbReader.ensIndexerSchema.v1Domain)
.limit(10);
.limit(10);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This TypeScript snippet won’t compile as written: it references ensIndexerSchema.v1Domain (elsewhere the docs use v1_domains), and the chained query is terminated early and then calls .limit(10) again on a new statement. Please update the example to use the correct table property name and a single, properly chained query.

Suggested change
.from(ensDbReader.ensIndexerSchema.v1Domain)
.limit(10);
.limit(10);
.from(ensDbReader.ensIndexerSchema.v1_domains)
.limit(10);

Copilot uses AI. Check for mistakes.

## ENS Namespace Isolation

The most critical operational decision is how to handle [ENS Namespaces](/ensindexer/usage/ens-namespaces). An ENS Namespace (like "mainnet" or "sepolia") defines which chains an ENSIndexer instance indexes.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This link points to /ensindexer/usage/ens-namespaces, but that page doesn’t exist in the current docs tree (ensindexer/usage only has configuration and management). Please update the link to an existing page/anchor or add the missing ENS Namespaces doc page so readers don’t hit a 404.

Suggested change
The most critical operational decision is how to handle [ENS Namespaces](/ensindexer/usage/ens-namespaces). An ENS Namespace (like "mainnet" or "sepolia") defines which chains an ENSIndexer instance indexes.
The most critical operational decision is how to handle [ENS Namespaces](/ensindexer/usage/configuration). An ENS Namespace (like "mainnet" or "sepolia") defines which chains an ENSIndexer instance indexes.

Copilot uses AI. Check for mistakes.

### Ponder Schema

A [database schema](#database-schema) in the [ENSDb instance](#ensdb-instance) following the [Ponder Schema Definition](#ponder-schema-definition). It has a fixed `ponder_sync` name, and it serves as a shared RPC cache for all [ENSIndexer instances](#ensindexer-instance) connected to the [ENSDb instance](#ensdb-instance). It's lifecycle is managed by Ponder runtime.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

Grammar: “It's lifecycle” should be “Its lifecycle” (possessive, not “it is”).

Suggested change
A [database schema](#database-schema) in the [ENSDb instance](#ensdb-instance) following the [Ponder Schema Definition](#ponder-schema-definition). It has a fixed `ponder_sync` name, and it serves as a shared RPC cache for all [ENSIndexer instances](#ensindexer-instance) connected to the [ENSDb instance](#ensdb-instance). It's lifecycle is managed by Ponder runtime.
A [database schema](#database-schema) in the [ENSDb instance](#ensdb-instance) following the [Ponder Schema Definition](#ponder-schema-definition). It has a fixed `ponder_sync` name, and it serves as a shared RPC cache for all [ENSIndexer instances](#ensindexer-instance) connected to the [ENSDb instance](#ensdb-instance). Its lifecycle is managed by Ponder runtime.

Copilot uses AI. Check for mistakes.
SELECT * FROM "ensnode"."metadata"
WHERE ens_indexer_schema_name = 'ensindexer_mainnet'
AND key = 'ensindexer_indexing_status'
AND value -> 'data' -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The indexing-status query here uses a deeply nested JSON path (value -> 'data' -> 'omnichainSnapshot' ...) and an omnichain-following status string, but other pages in this docs set show the indexing status as value->>'status' with backfill/following (e.g. ensdb/usage/querying.mdx). This inconsistency will confuse readers—please align these examples (or explain the two different formats if both exist).

Suggested change
AND value -> 'data' -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';
AND value->>'status' = 'following';

Copilot uses AI. Check for mistakes.
Comment on lines +144 to +157
The `key` column identifies the type of metadata:

| Key | Description |
|-----|-------------|
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |

#### Indexing Metadata Context

A JSON object that provides context about the ENSNode stack the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance).
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The glossary lists indexing_metadata_context as the only ENSNode metadata key, but the rest of these docs use keys like ensdb_version, ensindexer_public_config, and ensindexer_indexing_status. Please reconcile this section with the keys used elsewhere (either update the list, or explain how indexing_metadata_context relates to those keys).

Suggested change
The `key` column identifies the type of metadata:
| Key | Description |
|-----|-------------|
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |
#### Indexing Metadata Context
A JSON object that provides context about the ENSNode stack the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance).
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to.
The `key` column identifies the type of metadata record stored in the table. In the current model documented here, the metadata is stored under a single top-level key:
| Key | Description |
|-----|-------------|
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |
Other names used elsewhere in the documentation, such as `ensdb_version`, `ensindexer_public_config`, and `ensindexer_indexing_status`, should be understood as versioned fields or logical sections within the JSON `value` of this metadata record, rather than additional values of the `key` column.
#### Indexing Metadata Context
A JSON object that provides context about the ENSNode stack and the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance). Elsewhere this may be referred to as `ensindexer_indexing_status`.
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to. Elsewhere this may be referred to as `ensdb_public_config`, with version information represented by values such as `ensdb_version`.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to. Elsewhere this may be referred to as `ensindexer_public_config`.

Copilot uses AI. Check for mistakes.
FROM ensindexer_mainnet.events e
JOIN ensindexer_mainnet.domain_events de ON e.id = de.event_id
JOIN ensindexer_mainnet.v1_domains d ON de.domain_id = d.id
WHERE e.selector = '\x0x...' -- NewOwner event
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

In this SQL example, the bytea literal \x prefix is written as \x0x..., which isn’t valid PostgreSQL input syntax (it will be interpreted as hex starting with 0x...). Use a proper \x... hex string (or show the selector as a normal 0x... string if it’s not meant to be a bytea literal).

Suggested change
WHERE e.selector = '\x0x...' -- NewOwner event
WHERE e.selector = '\x...' -- NewOwner event

Copilot uses AI. Check for mistakes.
Reader["Reader<br/>(API)"]
end

ENSDb["ENSDb<br/>(SQLite)"]
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This architecture diagram labels ENSDb as “SQLite”, but elsewhere (and in the ENSDb definition) ENSDb is explicitly a PostgreSQL database. Using SQLite here is misleading; update the diagram to “PostgreSQL” (or clarify that this pattern is not applicable to ENSDb).

Suggested change
ENSDb["ENSDb<br/>(SQLite)"]
ENSDb["ENSDb<br/>(PostgreSQL)"]

Copilot uses AI. Check for mistakes.

<LinkCard
title="ENSDb SDK"
description="TypeScript utilities for typing-safe ENSDb access"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

Typo in link card description: “typing-safe” should be “type-safe”.

Suggested change
description="TypeScript utilities for typing-safe ENSDb access"
description="TypeScript utilities for type-safe ENSDb access"

Copilot uses AI. Check for mistakes.
Comment thread docs/ensnode.io/src/content/docs/ensdb/index.mdx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
docs/ensnode.io/src/content/docs/ensdb/index.mdx (1)

207-222: ⚠️ Potential issue | 🟠 Major

EnsDbReader constructor signature doesn't match the actual SDK API.

Per packages/ensdb-sdk/src/client/ensdb-reader.ts, the constructor is new EnsDbReader(config: EnsDbConfig, abstractEnsIndexerSchema) — it takes two objects ({ connectionString } and an abstract schema), not two bare strings. Users copying this snippet will get type errors. The JSDoc @example in the SDK source is the authoritative shape.

Also, ensDbReader.ensIndexerSchema.v1Domain should be v1_domains to match the schema member used in the SQL examples on line 193 (this was flagged previously and is still present).

🛠️ Proposed fix
 import { EnsDbReader } from '@ensnode/ensdb-sdk';
+import { EnsIndexerSchema } from '@ensnode/ensdb-sdk/ensindexer-abstract';

 // Connect to a specific ENSDb instance by providing its connection string and
 // the ENSIndexer Schema Name you want to query
-const ensDbReader =  new EnsDbReader(ensDbConnectionString, ensIndexerSchemaName);
+const ensDbReader = new EnsDbReader(
+  { connectionString: ensDbConnectionString },
+  { schemaName: ensIndexerSchemaName },
+);

-// Get domains from the ENSIndexer Schema 
-const v1Domains = await
- ensDbReader.ensDb.select()
-  .from(ensDbReader.ensIndexerSchema.v1Domain)
-  .limit(10);
+// Get domains from the ENSIndexer Schema
+const v1Domains = await ensDbReader.ensDb
+  .select()
+  .from(ensDbReader.ensIndexerSchema.v1_domains)
+  .limit(10);

 // Get indexing status
-const indexingStatus = await ensDbReader.getIndexingStatusSnapshot()
+const indexingStatus = await ensDbReader.getIndexingStatusSnapshot();
#!/bin/bash
# Confirm the actual EnsDbReader constructor signature and the schema member name used by EnsIndexer's abstract schema.
fd -t f 'ensdb-reader.ts' | xargs -I{} sh -c 'echo "=== {} ==="; sed -n "1,160p" "{}"'
echo "---- searching schema member names ----"
rg -nP '\b(v1_domains|v1Domain)\b' --type=ts -C1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/index.mdx` around lines 207 - 222, The
example uses the wrong EnsDbReader signature and schema member names: replace
the two-string constructor call with the correct objects (pass an
EnsDbConfig-like object, e.g., { connectionString: ... }, as the first argument
and the abstractEnsIndexerSchema as the second) and update any schema access
from ensDbReader.ensIndexerSchema.v1Domain to
ensDbReader.ensIndexerSchema.v1_domains so it matches the actual SDK symbols
(refer to EnsDbReader, EnsDbConfig, and abstractEnsIndexerSchema in
packages/ensdb-sdk/src/client/ensdb-reader.ts).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.letta/settings.json:
- Line 11: Remove or restrict the overly broad permission rule
"Edit(//Users/tko/dev/github/namehash/**)"; either delete this entry entirely or
replace it with a scoped pattern that only allows edits to the intended
documentation directories (e.g., specific doc paths already listed) so the rule
no longer grants write access to the entire namehash tree.
- Around line 4-6: The three Bash(...) entries containing absolute user-specific
paths should be changed to relative paths or project-root variables so they work
on any machine; update the Bash strings (e.g., the entries starting with
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/...") to use relative
equivalents like "Bash(mkdir -p
./docs/ensnode.io/src/content/docs/ensdb/concepts)" or use a
placeholder/project-root variable (e.g., ${PROJECT_ROOT}) consistently for each
of the three lines so they no longer reference a specific home directory.

In @.letta/settings.local.json:
- Around line 1-13: This file (.letta/settings.local.json) contains local user
session state ("lastAgent", "sessionsByServer", "lastSession") and must not be
committed; remove it from version control with git rm --cached
.letta/settings.local.json, add the pattern .letta/settings.local.json (or
.letta/) to .gitignore so it is ignored going forward, and optionally add a
template like .letta/settings.local.json.example containing placeholder keys
("lastAgent", "sessionsByServer", "lastSession") to document the schema for
other developers.

In `@docs/ensnode.io/src/content/docs/ensdb/index.mdx`:
- Around line 95-110: The prose under "Example: Multi-Instance Server" and the
Mermaid diagram use inconsistent environment names (e.g., "sepolia"/"ENSDb
Sepolia instance" and "ens-test-env"/"ENSDb ENS Test Env instance") versus the
Quick Start variable names (`ensdb_mainnet`, `ensdb_testnet`, `ensdb_devnet`);
pick one naming convention (for example: mainnet/sepolia/devnet or
mainnet/testnet/devnet) and make them consistent by updating the paragraph text,
the Mermaid node labels (e.g., change "ENSDb Sepolia instance" and "ENSDb ENS
Test Env instance"), and any Quick Start references (`ensdb_mainnet`,
`ensdb_testnet`, `ensdb_devnet`) so the same names appear everywhere. Ensure the
chosen names are applied to the heading "Example: Multi-Instance Server", the
bulleted examples, and the Mermaid nodes so readers can unambiguously map each
environment to its database instance.
- Line 165: The sentence contains a stray word "you" ("assume you that ENSDb
instances are served") which breaks grammar; remove "you" and change the phrase
to "assume that ENSDb instances are served" so the sentence reads cleanly and
grammatically correct in the ENSDb docs example.

---

Duplicate comments:
In `@docs/ensnode.io/src/content/docs/ensdb/index.mdx`:
- Around line 207-222: The example uses the wrong EnsDbReader signature and
schema member names: replace the two-string constructor call with the correct
objects (pass an EnsDbConfig-like object, e.g., { connectionString: ... }, as
the first argument and the abstractEnsIndexerSchema as the second) and update
any schema access from ensDbReader.ensIndexerSchema.v1Domain to
ensDbReader.ensIndexerSchema.v1_domains so it matches the actual SDK symbols
(refer to EnsDbReader, EnsDbConfig, and abstractEnsIndexerSchema in
packages/ensdb-sdk/src/client/ensdb-reader.ts).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8e7c0404-9c96-4c9d-9365-6e9a52492543

📥 Commits

Reviewing files that changed from the base of the PR and between 00befeb and 3a8c453.

📒 Files selected for processing (4)
  • .letta/.lettaignore
  • .letta/settings.json
  • .letta/settings.local.json
  • docs/ensnode.io/src/content/docs/ensdb/index.mdx

Comment thread .letta/settings.json Outdated
Comment on lines +4 to +6
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/concepts)",
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage)",
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage/sdk)",
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.

⚠️ Potential issue | 🔴 Critical

Replace hardcoded absolute paths with relative paths.

The absolute paths /Users/tko/dev/github/namehash/ensnode/... are specific to your local machine and username. They will fail for other contributors with different usernames or directory structures.

♻️ Proposed fix using relative paths
-      "Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/concepts)",
-      "Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage)",
-      "Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage/sdk)",
+      "Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/concepts)",
+      "Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/usage)",
+      "Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/usage/sdk)",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/concepts)",
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage)",
"Bash(mkdir -p /Users/tko/dev/github/namehash/ensnode/docs/ensnode.io/src/content/docs/ensdb/usage/sdk)",
"Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/concepts)",
"Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/usage)",
"Bash(mkdir -p docs/ensnode.io/src/content/docs/ensdb/usage/sdk)",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.letta/settings.json around lines 4 - 6, The three Bash(...) entries
containing absolute user-specific paths should be changed to relative paths or
project-root variables so they work on any machine; update the Bash strings
(e.g., the entries starting with "Bash(mkdir -p
/Users/tko/dev/github/namehash/ensnode/...") to use relative equivalents like
"Bash(mkdir -p ./docs/ensnode.io/src/content/docs/ensdb/concepts)" or use a
placeholder/project-root variable (e.g., ${PROJECT_ROOT}) consistently for each
of the three lines so they no longer reference a specific home directory.

Comment thread .letta/settings.json Outdated
"Edit(docs/ensnode.io/src/content/docs/ensdb/**)",
"Edit(docs/ensdb/concepts/**)",
"Edit(docs/ensdb/usage/sdk/**)",
"Edit(//Users/tko/dev/github/namehash/**)"
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.

⚠️ Potential issue | 🟠 Major

Remove overly permissive edit rule.

The pattern Edit(//Users/tko/dev/github/namehash/**) grants permission to edit any file under the entire namehash directory tree, far beyond the scope of this PR's documentation changes. This violates the principle of least privilege and poses a security risk.

🛡️ Recommended fix

If you need broader edit permissions beyond the specific paths already listed (lines 7-10), scope them to only the documentation directories:

-      "Edit(//Users/tko/dev/github/namehash/**)"
+      "Edit(docs/**)"

Or remove this line entirely if the specific paths on lines 7-10 are sufficient.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"Edit(//Users/tko/dev/github/namehash/**)"
"Edit(docs/**)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.letta/settings.json at line 11, Remove or restrict the overly broad
permission rule "Edit(//Users/tko/dev/github/namehash/**)"; either delete this
entry entirely or replace it with a scoped pattern that only allows edits to the
intended documentation directories (e.g., specific doc paths already listed) so
the rule no longer grants write access to the entire namehash tree.

Comment thread .letta/settings.local.json Outdated
Comment on lines +1 to +13
{
"lastAgent": "agent-8f1fd90c-1e78-4f11-8a13-d909be3d330b",
"sessionsByServer": {
"api.letta.com": {
"agentId": "agent-8f1fd90c-1e78-4f11-8a13-d909be3d330b",
"conversationId": "default"
}
},
"lastSession": {
"agentId": "agent-8f1fd90c-1e78-4f11-8a13-d909be3d330b",
"conversationId": "default"
}
}
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.

⚠️ Potential issue | 🟠 Major

Do not commit local state files; add to .gitignore.

This file contains user-specific session state (agent IDs, conversation IDs) that is local to your development environment. Committing it to version control will:

  • Cause merge conflicts when other developers' local state differs
  • Leak environment-specific runtime state that has no meaning for other contributors
  • Override other users' local configuration when they pull changes
🔧 Recommended fix
  1. Remove this file from version control:
git rm --cached .letta/settings.local.json
  1. Add the pattern to .gitignore:
+# Letta local state
+.letta/settings.local.json
  1. Optionally, create a .letta/settings.local.json.example template file with placeholder values to document the expected schema for other developers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.letta/settings.local.json around lines 1 - 13, This file
(.letta/settings.local.json) contains local user session state ("lastAgent",
"sessionsByServer", "lastSession") and must not be committed; remove it from
version control with git rm --cached .letta/settings.local.json, add the pattern
.letta/settings.local.json (or .letta/) to .gitignore so it is ignored going
forward, and optionally add a template like .letta/settings.local.json.example
containing placeholder keys ("lastAgent", "sessionsByServer", "lastSession") to
document the schema for other developers.

Comment on lines +95 to +110
### Example: Multi-Instance Server

A single PostgreSQL server can serve multiple ENSDb instances for different ENS Namespaces. This allows you to have separate ENSDb instances based on your needs. For example:
- Your production environment can have a dedicated ENSDb instance for ENS data from the ENS Namespace "mainnet".
- Your staging environment can have a separate ENSDb instance for ENS data from the ENS Namespace "sepolia".
- Your local development environment can have its own ENSDb instance for testing with local or ephemeral data from the ENS Namespace "ens-test-env".

```mermaid
flowchart TB
subgraph PGServer["PostgreSQL Server"]
direction TB
Mainnet[(ENSDb Mainnet instance)]
Testnet[(ENSDb Sepolia instance)]
Devnet[(ENSDb ENS Test Env instance)]
end
```
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.

⚠️ Potential issue | 🟡 Minor

Diagram/prose inconsistency: "sepolia" vs. "Testnet" vs. ensdb_testnet.

Lines 97–100 describe three environments keyed by ENS namespace (mainnet, sepolia, ens-test-env), but the diagram below labels the middle instance ENSDb Sepolia instance and the last ENSDb ENS Test Env instance, while the Quick Start block (L169–175) uses ensdb_mainnet/ensdb_testnet/ensdb_devnet. Consider aligning these names (e.g., pick either sepolia/ens-test-env or testnet/devnet consistently) so readers aren't confused about which database corresponds to which environment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ensnode.io/src/content/docs/ensdb/index.mdx` around lines 95 - 110, The
prose under "Example: Multi-Instance Server" and the Mermaid diagram use
inconsistent environment names (e.g., "sepolia"/"ENSDb Sepolia instance" and
"ens-test-env"/"ENSDb ENS Test Env instance") versus the Quick Start variable
names (`ensdb_mainnet`, `ensdb_testnet`, `ensdb_devnet`); pick one naming
convention (for example: mainnet/sepolia/devnet or mainnet/testnet/devnet) and
make them consistent by updating the paragraph text, the Mermaid node labels
(e.g., change "ENSDb Sepolia instance" and "ENSDb ENS Test Env instance"), and
any Quick Start references (`ensdb_mainnet`, `ensdb_testnet`, `ensdb_devnet`) so
the same names appear everywhere. Ensure the chosen names are applied to the
heading "Example: Multi-Instance Server", the bulleted examples, and the Mermaid
nodes so readers can unambiguously map each environment to its database
instance.

Comment thread docs/ensnode.io/src/content/docs/ensdb/index.mdx Outdated

### Ponder Schema

A [database schema](#database-schema) in the [ENSDb instance](#ensdb-instance) following the [Ponder Schema Definition](#ponder-schema-definition). It has a fixed `ponder_sync` name, and it serves as a shared RPC cache for all [ENSIndexer instances](#ensindexer-instance) connected to the [ENSDb instance](#ensdb-instance). It's lifecycle is managed by Ponder runtime.
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Apr 17, 2026

Choose a reason for hiding this comment

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

Grammar error: "It's lifecycle" should be "Its lifecycle" - incorrect use of contraction instead of possessive pronoun.

Fix on Vercel


#### Ponder Schema Definition

A [Schema Definition](#schema-definition) that defines the structure of the [Ponder Schema](#ponder-schema) in the [ENSDb instance](#ensdb-instance). This Schema Definition is an implementation detail of Ponder, so we treat is as an opaque black box in ENSDb documentation.
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Apr 17, 2026

Choose a reason for hiding this comment

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

Grammar error: "treat is as" should be "treat it as" in the Ponder Schema Definition section

Fix on Vercel

Comment on lines +215 to +216
const v1Domains = await
ensDbReader.ensDb.select()
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Apr 17, 2026

Choose a reason for hiding this comment

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

TypeScript code example has improper line break after await keyword, making the code non-idiomatic and harder to read

Fix on Vercel

SELECT * FROM "ensnode"."metadata"
WHERE ens_indexer_schema_name = 'ensindexer_mainnet'
AND key = 'ensindexer_indexing_status'
AND value -> 'data' -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Apr 17, 2026

Choose a reason for hiding this comment

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

SQL query uses incorrect JSON path for querying indexing status metadata

Fix on Vercel

Copilot AI review requested due to automatic review settings April 17, 2026 06:52
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 17, 2026 06:52 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 17, 2026 06:52 Inactive
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +40
const ensDbReader = new EnsDbReader(ensDbConnectionString, ensIndexerSchemaName);

// Get domains from the ENSIndexer Schema
const v1Domains = await
ensDbReader.ensDb.select()
.from(ensDbReader.ensIndexerSchema.v1Domain)
.limit(10);

// Get indexing status
const indexingStatus = await ensDbReader.getIndexingStatusSnapshot()
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The TypeScript example as written won’t parse/copy-paste cleanly (line break after await, inconsistent indentation, missing semicolon at the end). Consider formatting this snippet as valid TypeScript so users can run it directly.

Suggested change
const ensDbReader = new EnsDbReader(ensDbConnectionString, ensIndexerSchemaName);
// Get domains from the ENSIndexer Schema
const v1Domains = await
ensDbReader.ensDb.select()
.from(ensDbReader.ensIndexerSchema.v1Domain)
.limit(10);
// Get indexing status
const indexingStatus = await ensDbReader.getIndexingStatusSnapshot()
const ensDbReader = new EnsDbReader(ensDbConnectionString, ensIndexerSchemaName);
// Get domains from the ENSIndexer Schema
const v1Domains = await ensDbReader.ensDb
.select()
.from(ensDbReader.ensIndexerSchema.v1Domain)
.limit(10);
// Get indexing status
const indexingStatus = await ensDbReader.getIndexingStatusSnapshot();

Copilot uses AI. Check for mistakes.

### Connect with Any PostgreSQL Client

Connect to an ENSDb instance (a PostgreSQL database). The examples below assume you that ENSDb instances are served from a PostgreSQL server at `host:5432` with databases named `ensdb_mainnet`, `ensdb_testnet`, and `ensdb_devnet`:
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

Grammar: “assume you that” reads incorrectly. Consider changing to “assume that” (or rephrasing the sentence).

Suggested change
Connect to an ENSDb instance (a PostgreSQL database). The examples below assume you that ENSDb instances are served from a PostgreSQL server at `host:5432` with databases named `ensdb_mainnet`, `ensdb_testnet`, and `ensdb_devnet`:
Connect to an ENSDb instance (a PostgreSQL database). The examples below assume that ENSDb instances are served from a PostgreSQL server at `host:5432` with databases named `ensdb_mainnet`, `ensdb_testnet`, and `ensdb_devnet`:

Copilot uses AI. Check for mistakes.
SELECT * FROM "ensnode"."metadata"
WHERE ens_indexer_schema_name = 'ensindexer_mainnet'
AND key = 'ensindexer_indexing_status'
AND value -> 'data' -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The JSON path in this SQL example doesn’t match the serialized shape used by the SDK for ensindexer_indexing_status (it’s not wrapped under data). Based on serializeCrossChainIndexingStatusSnapshot, omnichainStatus lives under value -> 'omnichainSnapshot' ->> 'omnichainStatus'. Updating the query will prevent users from copying an example that returns no rows.

Suggested change
AND value -> 'data' -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';
AND value -> 'omnichainSnapshot' ->> 'omnichainStatus' = 'omnichain-following';

Copilot uses AI. Check for mistakes.
- All [ENSIndexer instances](#ensindexer-instance) share the [Ponder Schema](#ponder-schema), including the RPC cache.
- Metadata of all [ENSIndexer instances](#ensindexer-instance) is tracked in the [ENSNode Schema](#ensnode-schema)

This enables separate indexing by multiple [ENSIndexer instance](#ensindexer-instance) with different configs. The configs may require indexing just certain chains. For example, one [ENSIndexer instance](#ensindexer-instance) is configured to index data just from the Ethereum Mainnet, while another [ENSIndexer instance](#ensindexer-instance) is configured to index data from both, Ethereum Mainnet, and Base Mainnet. Each of these [ENSIndexer instances](#ensindexer-instance) would have its own [ENSIndexer Schema](#ensindexer-schema) in the same [ENSDb instance](#ensdb-instance).
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

Grammar: “multiple ENSIndexer instance” should be plural (“instances”).

Suggested change
This enables separate indexing by multiple [ENSIndexer instance](#ensindexer-instance) with different configs. The configs may require indexing just certain chains. For example, one [ENSIndexer instance](#ensindexer-instance) is configured to index data just from the Ethereum Mainnet, while another [ENSIndexer instance](#ensindexer-instance) is configured to index data from both, Ethereum Mainnet, and Base Mainnet. Each of these [ENSIndexer instances](#ensindexer-instance) would have its own [ENSIndexer Schema](#ensindexer-schema) in the same [ENSDb instance](#ensdb-instance).
This enables separate indexing by multiple [ENSIndexer instances](#ensindexer-instance) with different configs. The configs may require indexing just certain chains. For example, one [ENSIndexer instance](#ensindexer-instance) is configured to index data just from the Ethereum Mainnet, while another [ENSIndexer instance](#ensindexer-instance) is configured to index data from both, Ethereum Mainnet, and Base Mainnet. Each of these [ENSIndexer instances](#ensindexer-instance) would have its own [ENSIndexer Schema](#ensindexer-schema) in the same [ENSDb instance](#ensdb-instance).

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +159
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |

#### Indexing Metadata Context

A JSON object that provides context about the ENSNode stack the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance).
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to.
- `ensRainbowPublicConfig`: the public config of the ENSRainbow instance that this [ENSIndexer instance](#ensindexer-instance) is connected to. Might be `null` during the ENSNode stack cold start, when the ENSIndexer instance starts before the ENSRainbow instance.

Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The metadata key list here doesn’t match the keys used by the ENSDb SDK (ensdb_version, ensindexer_public_config, ensindexer_indexing_status). Using a different key name (indexing_metadata_context) will mislead readers and conflicts with the SQL example in /ensdb/usage/sql.

Suggested change
| `indexing_metadata_context` | [Indexing metadata context](#indexing-metadata-context) of the [ENSIndexer instance](#ensindexer-instance) |
#### Indexing Metadata Context
A JSON object that provides context about the ENSNode stack the Indexing Status. It includes:
- `version`: The version of the Indexing Metadata Context structure
- `data`: The actual context data, whose structure may evolve over time as the needs of the ENSNode stack evolve. The `data` object may include fields such as:
- `indexingStatus`: the current Indexing Status of the [ENSIndexer instance](#ensindexer-instance).
- `ensDbPublicConfig`: the public config of the [ENSDb instance](#ensdb-instance) that this [ENSIndexer instance](#ensindexer-instance) is connected to.
- `ensIndexerPublicConfig`: the public config of the [ENSIndexer instance](#ensindexer-instance) that this metadata record belongs to.
- `ensRainbowPublicConfig`: the public config of the ENSRainbow instance that this [ENSIndexer instance](#ensindexer-instance) is connected to. Might be `null` during the ENSNode stack cold start, when the ENSIndexer instance starts before the ENSRainbow instance.
| `ensdb_version` | Version metadata for the connected [ENSDb instance](#ensdb-instance) |
| `ensindexer_public_config` | Public configuration metadata for the [ENSIndexer instance](#ensindexer-instance) |
| `ensindexer_indexing_status` | Current indexing status metadata for the [ENSIndexer instance](#ensindexer-instance) |
#### ENSDb Version
A JSON object describing the version information for the connected [ENSDb instance](#ensdb-instance). As with other metadata records, the object is versioned and includes a top-level `version` field so its structure can evolve safely over time.
#### ENSIndexer Public Config
A JSON object containing the public configuration of the [ENSIndexer instance](#ensindexer-instance) that owns the metadata record. The object is versioned and includes a top-level `version` field.
#### ENSIndexer Indexing Status
A JSON object containing the current indexing status of the [ENSIndexer instance](#ensindexer-instance). The object is versioned and includes a top-level `version` field.

Copilot uses AI. Check for mistakes.
Comment on lines +260 to 265
#starlight__sidebar>div>ul>li:not(:first-child):not(:last-child)::before {
content: "";
position: absolute;
left: 8px; /* X-position of the vertical line */
left: 8px;
/* X-position of the vertical line */
top: 0;
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The same selector #starlight__sidebar>div>ul>li:not(:first-child):not(:last-child)::before is defined twice (here and again a few lines below) just to override height. Consider merging into a single rule to avoid duplication and make future edits less error-prone.

Copilot uses AI. Check for mistakes.
title: ENSNode Reference Implementation
description: Overview of ENSNode, the reference implementation of the ENSDb standard, including its components and architecture.
sidebar:
label: ENSNode Reference Implementation
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

Frontmatter label has an extra leading space, which will likely show up in the rendered sidebar label.

Suggested change
label: ENSNode Reference Implementation
label: ENSNode Reference Implementation

Copilot uses AI. Check for mistakes.
Comment on lines +138 to +141
Primary key: (`ens_indexer_schema_name`, `key`)

The `value` column stores a JSON object which structure may evolve over time. To track this, the JSON object is guaranteed to always include a `version` field indicating the version of the structure. This allows for future-proofing as the metadata needs evolve.

Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

This claims the value column always stores a JSON object with a guaranteed version field. In the current SDK, ensdb_version is stored as a JSON string, and other records (e.g. indexing status snapshot) serialize without a {version, data} wrapper. Consider revising this to describe the actual per-key value shapes rather than guaranteeing an object with version.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants