[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80316":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":42,"readmeContent":43,"aiSummary":44,"trendingCount":16,"starSnapshotCount":16,"syncStatus":45,"lastSyncTime":46,"discoverSource":47},80316,"dualmark","dodopayments\u002Fdualmark","dodopayments","Open-source AEO (Answer Engine Optimization) infrastructure — every page, dual-marked. Markdown twins for AI agents alongside HTML for humans, picked by HTTP content negotiation.","https:\u002F\u002Fdualmark.dev",null,"TypeScript",84,26,1,12,0,5,8,17,15,4.29,"Apache License 2.0",false,"main",true,[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"aeo","ai-bots","ai-search","ai-seo","answer-engine-optimization","astro-integration","cloudflare-workers","content-negotiation","generative-engine-optimization","geo","llms-txt","markdown","nextjs","open-source","typescript","2026-06-12 02:04:00","# Dualmark\n\n\u003Cp align=\"left\">\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@dualmark\u002Fcore\">\n    \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fv\u002F@dualmark\u002Fcore?label=npm&color=blue\" alt=\"npm version\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdodopayments\u002Fdualmark\u002Fblob\u002Fmain\u002FLICENSE\">\n    \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache%202.0-green\" alt=\"License\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@dualmark\u002Fcore\">\n    \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fnpm-provenance-blueviolet?logo=npm\" alt=\"npm provenance\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FbYqAp4ayYh\">\n    \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F1305511580854779984?label=Join%20Discord&logo=discord\" alt=\"Join Discord\" \u002F>\n  \u003C\u002Fa>\n\u003C\u002Fp>\n\n> The AEO infrastructure your marketing site is missing.\n\nYour blog ranks #1 on Google. ChatGPT cites your competitor.\n\nThat's not a content problem. It's an **infrastructure problem**. AI search engines (ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews) read the web differently from humans — they want clean markdown without nav chrome, JavaScript, or cookie banners. Most marketing sites give them HTML soup and wonder why they get ignored.\n\n**Dualmark gives every page a markdown twin.** Same URL. Two formats. Picked by HTTP content negotiation. Drop it into your Astro\u002FNext.js\u002FCloudflare stack in 30 seconds. Score it with `dualmark verify`.\n\n```diff\n- npm install @next-seo\u002Fsome-meta-tag-thing\n+ bun add @dualmark\u002Fastro\n```\n\n[Quickstart](#quickstart) · [Why](#why-marketing-teams-need-this) · [Examples](.\u002Fexamples) · [Spec](.\u002Fspec) · [Docs](https:\u002F\u002Fdualmark.dev)\n\n---\n\n## Quickstart\n\n### Astro (30 seconds)\n\n```bash\nbun add @dualmark\u002Fastro\n```\n\n```ts\n\u002F\u002F astro.config.mjs\nimport { defineConfig } from \"astro\u002Fconfig\";\nimport dualmark from \"@dualmark\u002Fastro\";\n\nexport default defineConfig({\n  site: \"https:\u002F\u002Fyourcompany.com\",\n  integrations: [\n    dualmark({\n      siteUrl: \"https:\u002F\u002Fyourcompany.com\",\n      collections: {\n        blog: { converter: \"blog\" },           \u002F\u002F \u002Fblog\u002F*.md auto-generated\n        glossary: { converter: \"glossary\" },   \u002F\u002F \u002Fglossary\u002F*.md auto-generated\n      },\n      llmsTxt: { enabled: true },              \u002F\u002F \u002Fllms.txt auto-generated\n    }),\n  ],\n});\n```\n\n```bash\nbun run build && bunx dualmark verify https:\u002F\u002Flocalhost:4321\u002Fblog\u002Fyour-post\n# → Score 80\u002F80 ✓\n```\n\nThat's it. Every blog post has a markdown twin at `\u002Fblog\u002F\u003Cslug>.md`. `llms.txt` is generated. Every HTML response advertises its twin via `Link: \u003C…>; rel=\"alternate\"; type=\"text\u002Fmarkdown\"`. ChatGPT crawler sees clean markdown. Your existing pages don't change.\n\n### Next.js App Router (60 seconds)\n\n```bash\nbun add @dualmark\u002Fnextjs\n```\n\n```ts\n\u002F\u002F proxy.ts (or middleware.ts on Next ≤15)\nimport { createDualmarkMiddleware } from \"@dualmark\u002Fnextjs\";\n\nexport default createDualmarkMiddleware({ siteUrl: \"https:\u002F\u002Fyourcompany.com\" });\n\nexport const config = {\n  matcher: [\n    {\n      source: \"\u002F((?!_next\u002F|favicon.ico|md\u002F).*)\",\n      missing: [{ type: \"header\", key: \"next-router-prefetch\" }],\n    },\n  ],\n};\n```\n\n```ts\n\u002F\u002F app\u002Fmd\u002F[...path]\u002Froute.ts\nimport { createDualmarkRouteHandler } from \"@dualmark\u002Fnextjs\";\nimport { POSTS } from \"@\u002Flib\u002Fposts\";\n\nconst handler = createDualmarkRouteHandler({\n  siteUrl: \"https:\u002F\u002Fyourcompany.com\",\n  collections: {\n    blog: { converter: \"blog\", getEntries: () => POSTS.map(toEntry) },\n  },\n});\n\nexport const dynamic = \"force-static\";\nexport const GET = handler.GET;\nexport const generateStaticParams = handler.generateStaticParams;\n```\n\nThat's it. Bot UAs get markdown, browsers get HTML with a `Link rel=\"alternate\"` header, direct `.md` URLs serve markdown. Full example with `next dev` → 120\u002F125 conformance score:\n\n[Full Next.js example →](.\u002Fexamples\u002Fnextjs-app-router)\n\n### Cloudflare Workers (60 seconds)\n\nWrap your existing Worker. AI bots get markdown at the edge — single-digit-ms first-byte from 300+ cities.\n\n```ts\nimport { createAEOWorker } from \"@dualmark\u002Fcloudflare\";\nimport upstream from \".\u002Fyour-existing-worker.js\";\n\nexport default createAEOWorker({\n  upstream,\n  trailingSlash: \"never\",\n  analytics: { binding: \"AI_AGENT_ANALYTICS\" },\n});\n```\n\n[Full example with `wrangler dev` → 125\u002F125 conformance score →](.\u002Fexamples\u002Fastro-cloudflare-full)\n\n---\n\n## Why marketing teams need this\n\nYou already invested in SEO. Now invest in AEO — for **a fraction of the effort**.\n\n| Problem | Without Dualmark | With Dualmark |\n|---|---|---|\n| **AI cites competitors instead of you** | Bots scrape your HTML, get nav menus + JS errors, pick the cleaner source | Same URL serves clean markdown to bots, polished HTML to humans |\n| **No way to know if you're discoverable** | \"We hope ChatGPT can read this\" | `dualmark verify` returns a 0–125 score with line-item failures |\n| **`llms.txt` proposal keeps changing** | Hand-maintained, drifts from sitemap | Auto-generated from the same config that drives your routes |\n| **Every team rebuilds this** | Custom middleware in every repo, none of them quite right | One battle-tested package, conforms to a public spec |\n| **No analytics for AI traffic** | \"Was that a bot or a human?\" | `onAIRequest` hook + Cloudflare Analytics Engine integration: bot name, vendor, page, tokens, country |\n| **Slow to roll out across pages** | Marketing waits weeks for engineering | Add `converter: \"compare\"` to a collection — done. Production-tested converters bundled. |\n\n**Built and battle-tested at [Dodo Payments](https:\u002F\u002Fdodopayments.com)** for our own marketing site. Now extracted as OSS so you don't have to write the same content negotiation, bot detection, and edge wrapping over and over.\n\n---\n\n## What you actually ship\n\n```\nyourcompany.com\u002Fpricing             ← human visitors get this\nyourcompany.com\u002Fpricing.md          ← AI agents get this\nyourcompany.com\u002Fllms.txt            ← AI agents discover everything\n```\n\nSame URL. Same content. Different rendering. Picked automatically by:\n- `Accept: text\u002Fmarkdown` header → markdown\n- Known AI bot User-Agent (GPTBot, ClaudeBot, PerplexityBot, +21 more) → markdown\n- Direct `.md` URL → markdown\n- Anything else → HTML, with `Link rel=\"alternate\"` pointing to the twin\n\nNo duplicate content penalties (markdown twin sets `X-Robots-Tag: noindex`). No JS framework rewrites. No content team retraining. **Your existing pages stay the same.**\n\n---\n\n## Built-in converters (`@dualmark\u002Fconverters`)\n\nDrop-in markdown generation for the page types every marketing site has:\n\n| Converter | What it's for | Marketing examples |\n|---|---|---|\n| `blog` | Long-form posts | Engineering blog, customer stories |\n| `case-study` | Customer wins | Logos with stats and pull-quote |\n| `changelog` | Release notes | \"What's new in v1.4\" with grouped changes |\n| `compare` | Us vs. competitor | \"Stripe alternative\" pages |\n| `docs` | Documentation | Getting started, API guides |\n| `feature` | Product\u002Ffeature pages | \"Webhooks\", \"SSO\" — problem\u002Fsolution + FAQ |\n| `glossary` | Term definitions | \"What is a payment gateway?\" |\n| `integration` | App marketplace \u002F integrations | \"Connect Stripe to Acme\", Slack connector pages |\n| `legal` | Policy pages | Terms, Privacy, DPA |\n| `pricing` | Pricing tables | Tier comparison with CTAs |\n| `pseo` | Programmatic SEO | \"SEO services in San Francisco\" with facts + cross-links |\n| `status-page` | Uptime \u002F status | Public component health + incidents |\n| `tool` | Standalone calculators | \"Currency converter\" |\n| `video` | Video landing pages | Webinar replays |\n\nEach converter takes your collection entry → returns clean markdown with the right structure for AI consumption (title, description, breadcrumbs, FAQ extraction, related links). No prompt engineering required.\n\n```ts\nimport { compareConverter } from \"@dualmark\u002Fconverters\";\n\nconst convert = compareConverter({\n  siteUrl: \"https:\u002F\u002Fyourcompany.com\",\n  basePath: \"\u002Fcompare\",\n});\n\nconst md = convert(yourComparePage);  \u002F\u002F → battle-tested markdown layout\n```\n\n---\n\n## Verify any site against the spec\n\n```bash\nbunx @dualmark\u002Fcli verify https:\u002F\u002Fyourcompany.com\u002Fpricing\n```\n\n```\nDualmark Conformance Report\nURL:         https:\u002F\u002Fyourcompany.com\u002Fpricing\nMarkdown:    https:\u002F\u002Fyourcompany.com\u002Fpricing.md\nScore:       125\u002F125\nDuration:    107ms\n\nPassed:\n  [+20] md.fetch         — Markdown twin URL is reachable\n  [+10] md.contentType   — Content-Type is text\u002Fmarkdown; charset=utf-8\n  [+10] md.tokensHeader  — X-Markdown-Tokens header is present\n  [+10] md.noindex       — X-Robots-Tag includes noindex\n  [+10] md.vary          — Vary header includes Accept\n  [+10] md.body          — Body is non-empty markdown\n  [+10] html.linkAlternate — HTML response advertises markdown twin\n  [+10] negotiation.botUa — GPTBot UA receives text\u002Fmarkdown\n  [+10] negotiation.acceptHeader — Accept: text\u002Fmarkdown receives text\u002Fmarkdown\n  ...\n```\n\nThree conformance levels — **Basic** (60%), **Standard** (80%), **Advanced** (95%). Drop the score in your CI to prevent regressions.\n\n```yaml\n# .github\u002Fworkflows\u002Fci.yml\n- run: bunx @dualmark\u002Fcli verify https:\u002F\u002Fstaging.yourcompany.com\u002Fpricing\n  # exits non-zero if any required check fails\n```\n\n---\n\n## What's in the box\n\n| Package | npm | Size | What it does |\n|---|---|---|---|\n| [`@dualmark\u002Fcore`](.\u002Fpackages\u002Fcore) | `npm i @dualmark\u002Fcore` | 14 KB | Framework-agnostic primitives: content negotiation (RFC 7231), AI-bot detection (24 known bots), markdown response builder, token estimation, composition helpers, `llms.txt` rendering. Zero runtime deps. |\n| [`@dualmark\u002Fconverters`](.\u002Fpackages\u002Fconverters) | `npm i @dualmark\u002Fconverters` | 16 KB | Production-tested converter factories. |\n| [`@dualmark\u002Fastro`](.\u002Fpackages\u002Fastro) | `npm i @dualmark\u002Fastro` | 22 KB | Astro 5 integration. Auto-generates `.md` endpoints, ships middleware, generates `llms.txt`. |\n| [`@dualmark\u002Fnextjs`](.\u002Fpackages\u002Fnextjs) | `npm i @dualmark\u002Fnextjs` | 15 KB | Next.js App Router adapter. `withDualmark()`, `createDualmarkMiddleware()`, `createDualmarkRouteHandler()`, `createLlmsTxtHandler()`. |\n| [`@dualmark\u002Fcloudflare`](.\u002Fpackages\u002Fcloudflare) | `npm i @dualmark\u002Fcloudflare` | 9 KB | Workers edge adapter. Wraps any upstream Worker. Hooks for analytics + telemetry. |\n| [`@dualmark\u002Fdeno`](.\u002Fpackages\u002Fdeno) | `npm i @dualmark\u002Fdeno` | 8 KB | Deno Deploy edge adapter. Wraps any Deno fetch handler. Lifecycle hooks scheduled on `info.completed`. |\n| [`@dualmark\u002Fcli`](.\u002Fpackages\u002Fcli) | `npm i -g @dualmark\u002Fcli` | 16 KB | `dualmark verify \u003Curl>`. Programmatic API too. |\n\nPlus:\n\n- [**`spec\u002F`**](.\u002Fspec) — the **AEO Specification v1.0**. Public, framework-agnostic, RFC-2119-compliant. Implement it in Go, Rust, PHP, Ruby — your call.\n- [**`apps\u002Fdocs\u002F`**](.\u002Fapps\u002Fdocs) — Fumadocs site at [dualmark.dev](https:\u002F\u002Fdualmark.dev)\n- [**`apps\u002Fdocs\u002Fapp\u002Fplay`**](.\u002Fapps\u002Fdocs\u002Fapp\u002Fplay) — interactive Accept-header + UA tester. Live at [dualmark.dev\u002Fplay](https:\u002F\u002Fdualmark.dev\u002Fplay).\n- [**`examples\u002F`**](.\u002Fexamples) — three end-to-end working examples (Astro, Astro+Cloudflare, Next.js).\n\n---\n\n## End-to-end verified\n\n| Surface | Status |\n|---|---|\n| `@dualmark\u002Fcore` | 174 tests pass (vitest + fast-check property tests) |\n| `@dualmark\u002Fconverters` | 31 tests pass |\n| `@dualmark\u002Fcloudflare` | 23 tests pass |\n| `@dualmark\u002Fdeno` | 23 tests pass |\n| `@dualmark\u002Fcli` | 17 tests pass |\n| `@dualmark\u002Fastro` | 36 tests pass |\n| `@dualmark\u002Fnextjs` | 47 tests pass |\n| `examples\u002Fastro-blog` | **80\u002F80** under `astro dev` (`--skip-negotiation`) |\n| `examples\u002Fastro-cloudflare-full` | **125\u002F125 perfect** under `wrangler dev` (full negotiation) |\n| `examples\u002Fnextjs-app-router` | **120\u002F125** under `next dev` (now using `@dualmark\u002Fnextjs`) |\n| `examples\u002Fdeno-deploy` | **125\u002F125 perfect** under `deno run` (full negotiation) |\n| `apps\u002Fdocs` | 26 routes prerendered, all serve 200 |\n| `\u002Fplay` route | Live at dualmark.dev\u002Fplay, integrated into the docs app |\n\n```bash\nbun install\nbun run build && bun run test && bun run typecheck   # 328 tests across 6 packages\n```\n\n---\n\n## Where it goes from here\n\nWe're building toward Dualmark being **the** AEO infrastructure for marketing sites — the same way Tailwind became the default for marketing CSS or Vercel for marketing hosting. The roadmap:\n\n- **More framework adapters**: SvelteKit, Remix\u002FReact Router, Nuxt\n- **More edge adapters**: Vercel, Netlify, Fastly Compute, Deno Deploy\n- **More converters**: pricing tables, changelog, docs\u002FAPI reference, status pages, integrations\n- **AEO Analytics**: a hosted dashboard on top of the `onAIRequest` hook, so marketing can see which bot reads which page, when\n- **Spec evolution toward AEO 1.1+** with structured data hints, per-section markdown anchors, and sitemap.md\n- **CMS integrations**: Sanity, Contentful, Builder.io plugins so non-engineers can author dual-marked content\n\nIf you're a marketing engineer reading this and any of those would land in your stack, [open an issue](https:\u002F\u002Fgithub.com\u002Fdodopayments\u002Fdualmark\u002Fissues) or [+1 an existing one](https:\u002F\u002Fgithub.com\u002Fdodopayments\u002Fdualmark\u002Fissues).\n\n---\n\n## Contributing\n\nWe're early. Issues, PRs, and \"I tried it on $framework and it broke\" reports are all welcome.\n\n- Read [CONTRIBUTING.md](.\u002FCONTRIBUTING.md) for the dev loop and release flow.\n- The AEO Spec is authoritative — if you implement it elsewhere (in any language), we want to link to your implementation.\n\n```bash\nbun install\nbun run build   # turbo-orchestrated build\nbun run test    # vitest across all packages\nbun run typecheck\n```\n\n## License\n\nApache 2.0 — see [LICENSE](.\u002FLICENSE) and [NOTICE](.\u002FNOTICE). Includes a patent grant. Use it for anything; attribution appreciated, never required.\n\n## Status\n\n**Pre-1.0.** APIs may change in patch releases until 1.0. The AEO Spec v1.0 is authoritative; framework code follows. Production-ready for early adopters; we're [running it on dodopayments.com](https:\u002F\u002Fdodopayments.com).\n","Dualmark 是一个开源的 AEO（Answer Engine Optimization）基础设施，旨在为每个网页提供一个 Markdown 版本，以优化 AI 代理的内容获取。其核心功能是通过 HTTP 内容协商机制，让同一 URL 同时支持 HTML 和 Markdown 两种格式输出，确保人类用户和 AI 代理都能获得最佳体验。项目采用 TypeScript 编写，并提供了与 Astro、Next.js 和 Cloudflare Workers 等流行框架的集成方案，使得开发者可以在 30 秒内快速部署 Dualmark 到现有项目中。此外，它还具备自动验证页面是否符合 AEO 标准的功能。适用于希望通过改善内容结构来提升搜索引擎排名及增加 AI 引擎引用率的企业网站或博客平台。",2,"2026-06-11 04:00:18","CREATED_QUERY"]