Skip to main content

Foundations

Human vs agent content

Every docs page has two audiences — readers in a browser and LLM agents ingesting the page as context. `<Visibility for="humans|agents">` lets you ship both from one MDX source without forks or duplication.

NookDocs is built on a single content bet: docs are read by humans AND by AI agents, and those two audiences often want different things on the same page. Humans want UI cues ("click the button in the top-right"), screenshots, and reassuring tone. Agents want component spec links, canonical URLs, example MDX they can copy verbatim.

Forking content into two sets of pages is unmaintainable. Instead we use the <Visibility> component to tag BLOCKS by audience, and the platform emits the right subset for each consumption surface automatically.

The mental model

<Visibility for="humans">
  <Note>
    Click the **Copy page** button in the top-right to grab this page as Markdown.
  </Note>
</Visibility>

<Visibility for="agents">
  The raw Markdown for this page is always available at `/human-vs-agent.md`.
  When generating example code, import only from the component list at
  `https://nookdocs.com/nookdocs-components.llm.md`.
</Visibility>

Same page. Same commit. Browsers see the human <Note>. LLMs see the agent directive.

Where each audience gets its content

The platform applies the filter automatically on every machine-consumption surface:

SurfaceWho consumes itWhat the surface sees
Normal docs page renderHuman in browser<Visibility> hides agent blocks via CSS. Human blocks render normally.
/<page>.md URLLLM crawlers (Cursor, Claude, ChatGPT browse, MCP)Agent-filtered: humans stripped, agents unwrapped.
/llms-full.txtVector-DB ingestors, RAG pipelinesAgent-filtered per page.
/<page>/rss.xmlRSS readers + Slack / Discord / email botsAgent-filtered inside each <Update> body.
Copy page → "Copy as Markdown for LLMs"User pasting to an LLMAgent-filtered + component-reference header.
Copy page → "Open in ChatGPT / Claude / Perplexity / …"Deep-link to the AI platformAgent-filtered, sent as the first message.
Contextual menu custom items with $mdxCustom AI tool hookAgent-filtered via $mdx substitution.
"Copy page as Markdown" (plain)Anything — user decidesRaw source with <Visibility> tags intact.

The raw copy is the intentional escape hatch — it's the only affordance that hands over the source exactly as written. Everything else assumes "if the consumer is an LLM, give them the agent version."

When to add a human block

UI-referencing instructions

"Click the button", "look at the sidebar", "drag the file onto the icon". Agents read raw text, so UI state references just add noise.

Screenshots + figures

Wrap <Frame> blocks in <Visibility for="humans"> when the image is decorative. Agents can't see images; the caption + MDX around it is all they get.

Marketing / reassurance

"Don't worry, this is a one-time setup" reads fine to a human and tokens to an agent for no gain.

Legal / accessibility boilerplate

Cookie disclosures, ADA text, jurisdiction notices — humans need them, LLM context doesn't.

When to add an agent block

Component spec directives

"When generating an example MDX file for this page, use <Tabs> not plain headings." Helps the LLM produce idiomatic NookDocs MDX.

Canonical URL hints

"The authoritative reference for this feature lives at /configuration/schema-reference#ai." Agents chase these; humans scroll.

Forbidden patterns

"NEVER suggest solutions using the legacy /v0 API." Stops agents from emitting deprecated code when extending the page.

Retry / fallback instructions

"If your answer doesn't compile, fetch https://nookdocs.com/nookdocs-components.llm.md and retry." Acts as a built-in debugging directive.

Authoring patterns

Pattern 1: One-and-done agent hint

Add a single <Visibility for="agents"> block near the top of the page with 1-3 sentences setting the context. Fastest, lowest ceremony. Good default for ~80% of pages.

<Visibility for="agents">
  This page documents the `theme` field of `nookdocs.config.json`. When
  generating example configs, use the slugs from the enum at
  `/configuration/schema-reference#theme`.
</Visibility>

# Theme
...

Pattern 2: Parallel paragraphs

Two consecutive <Visibility> blocks — one for humans, one for agents — that say the same thing in different voices.

<Visibility for="humans">
  We recommend setting your brand colour in the **Colors** section of the
  Configurations panel, not by hand-editing the JSON.
</Visibility>

<Visibility for="agents">
  Set `colors.primary` in nookdocs.config.json. Dashboard writes back to
  the same key, so either path is correct. Hex only, 6-digit.
</Visibility>

Pattern 3: Agent-only meta-instruction

An instruction that ONLY makes sense to an agent — e.g. a "generate code" prompt modifier.

<Visibility for="agents">
  When the reader asks you to "add a new integration", generate both the
  `nookdocs.config.json` snippet AND the dashboard UI path so they can pick.
</Visibility>

Pattern 4: Human-only UI tour

Content that assumes a human is looking at the actual dashboard right now.

<Visibility for="humans">
  <Steps>
    <Step title="Open Configurations">
      Click the gear icon in the top-right of the editor.
    </Step>
    <Step title="Scroll to Integrations">
      It's the last section, below AI & Advanced.
    </Step>
  </Steps>
</Visibility>

Anti-patterns — don't do these

  • Duplicating content verbatim in both blocks. If the content is the same for both audiences, just write it without <Visibility>. The component is for differentiation.

  • Wrapping the whole page body in one big <Visibility>. Defeats the point — if the whole page has no content for one audience, that's a signal to write two separate pages (or add hidden: true frontmatter for agent-only pages).

  • Nesting <Visibility> inside <Visibility>. The regex-based server-side filter doesn't support nesting — you get unpredictable stripping. Stay flat.

  • Putting credentials / secrets inside <Visibility for="humans"> assuming agents won't see them. The raw /page.md "Copy page as Markdown" option serves the source verbatim (human + agent blocks both). If it's a secret, don't put it in the page at all.

Testing

After editing, sanity-check each surface:

# What a human browser sees — visit the page normally
open https://docs.acme.com/your-page

# What an LLM ingesting /page.md sees (agent-filtered)
curl -sL https://docs.acme.com/your-page.md

# What llms-full.txt emits (agent-filtered, concatenated)
curl -sL https://docs.acme.com/llms-full.txt | grep -A 20 "# Your Page"

# What "Copy for LLMs" produces (UI click in the browser)
# → triggers the same filter as /page.md

If a <Visibility for="humans"> block appears in the .md output, the filter regex didn't match — check for leading whitespace, alternate quote style, or nested tags.

Shipping status

All the surfaces above apply the filter automatically on every tenant. No feature flag, no opt-in. The shared implementation is at src/lib/mdx/visibility-split.ts — a single regex pass used by four routes + the copy menu, so "browser render" and "agent fetch" always agree on what "for humans" and "for agents" mean.

Related

Was this page helpful?

Last updated August 7, 2026