@relvehq/agent-ready 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +364 -3
- package/SETUP.md +354 -0
- package/dist/bin/agent-ready.d.ts +23 -0
- package/dist/bin/agent-ready.js +444 -0
- package/dist/cli/init.d.ts +70 -0
- package/dist/cli/init.js +366 -0
- package/dist/core/accept.d.ts +8 -0
- package/dist/core/accept.js +76 -0
- package/dist/core/config.d.ts +145 -0
- package/dist/core/config.js +103 -0
- package/dist/core/convert.d.ts +22 -0
- package/dist/core/convert.js +334 -0
- package/dist/core/detect.d.ts +30 -0
- package/dist/core/detect.js +82 -0
- package/dist/core/easy.d.ts +19 -0
- package/dist/core/easy.js +117 -0
- package/dist/core/enrich.d.ts +30 -0
- package/dist/core/enrich.js +155 -0
- package/dist/core/llms.d.ts +11 -0
- package/dist/core/llms.js +71 -0
- package/dist/core/report.d.ts +15 -0
- package/dist/core/report.js +46 -0
- package/dist/core/resolve.d.ts +43 -0
- package/dist/core/resolve.js +204 -0
- package/dist/core/respond.d.ts +18 -0
- package/dist/core/respond.js +59 -0
- package/dist/core/sitemap.d.ts +31 -0
- package/dist/core/sitemap.js +140 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +76 -0
- package/dist/next/dashboard.d.ts +14 -0
- package/dist/next/dashboard.js +56 -0
- package/dist/next/index.d.ts +42 -0
- package/dist/next/index.js +100 -0
- package/dist/next/route.d.ts +26 -0
- package/dist/next/route.js +167 -0
- package/dist/node/index.d.ts +8 -0
- package/dist/node/index.js +191 -0
- package/dist/proof/audit.d.ts +47 -0
- package/dist/proof/audit.js +253 -0
- package/dist/proof/bots.d.ts +24 -0
- package/dist/proof/bots.js +60 -0
- package/dist/proof/dashboard.d.ts +8 -0
- package/dist/proof/dashboard.js +77 -0
- package/dist/proof/hits.d.ts +18 -0
- package/dist/proof/hits.js +51 -0
- package/dist/proof/jsonl.d.ts +5 -0
- package/dist/proof/jsonl.js +80 -0
- package/dist/proof/stats.d.ts +39 -0
- package/dist/proof/stats.js +127 -0
- package/dist/refine/check.d.ts +17 -0
- package/dist/refine/check.js +134 -0
- package/dist/refine/extract.d.ts +7 -0
- package/dist/refine/extract.js +120 -0
- package/dist/refine/file-store.d.ts +6 -0
- package/dist/refine/file-store.js +87 -0
- package/dist/refine/model.d.ts +30 -0
- package/dist/refine/model.js +105 -0
- package/dist/refine/prompts.d.ts +49 -0
- package/dist/refine/prompts.js +178 -0
- package/dist/refine/refine.d.ts +38 -0
- package/dist/refine/refine.js +75 -0
- package/dist/refine/remote.d.ts +57 -0
- package/dist/refine/remote.js +238 -0
- package/dist/refine/run.d.ts +52 -0
- package/dist/refine/run.js +66 -0
- package/dist/refine/types.d.ts +17 -0
- package/dist/refine/types.js +8 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-admin.php +550 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-converter.php +762 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-llms.php +192 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-markdown-builder.php +455 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-negotiation.php +334 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-refiner.php +894 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-response.php +226 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-router.php +421 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-settings.php +201 -0
- package/dist/wp/relve-agent-ready/includes/class-relve-ar-store.php +583 -0
- package/dist/wp/relve-agent-ready/includes/index.php +2 -0
- package/dist/wp/relve-agent-ready/index.php +2 -0
- package/dist/wp/relve-agent-ready/readme.txt +108 -0
- package/dist/wp/relve-agent-ready/relve-agent-ready.php +81 -0
- package/dist/wp/relve-agent-ready/uninstall.php +35 -0
- package/package.json +64 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Relve
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,364 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @relvehq/agent-ready
|
|
2
|
+
|
|
3
|
+
Make your site agent-ready. When an AI agent (ChatGPT, Claude, Perplexity,
|
|
4
|
+
Copilot…) asks for one of your pages as Markdown, it gets a clean, small
|
|
5
|
+
Markdown version instead of 50,000+ tokens of HTML. Browsers get exactly what
|
|
6
|
+
they got before.
|
|
7
|
+
|
|
8
|
+
- **Serve**: Markdown on `Accept: text/markdown`, on `<page>.md` and on
|
|
9
|
+
`?format=md`, plus a generated [`/llms.txt`](https://llmstxt.org). No AI
|
|
10
|
+
runs per request: it is plain code, in milliseconds.
|
|
11
|
+
- **Refine** (optional, with your own OpenAI key): one command writes a
|
|
12
|
+
better Markdown file for each page ahead of time with Relve's prompt, a
|
|
13
|
+
check compares every number and URL against the page, and unchanged pages
|
|
14
|
+
are skipped (free) on the next run.
|
|
15
|
+
- **Proof**: a free checker that scores any site out of 100, and a dashboard
|
|
16
|
+
of which AI agents read which pages.
|
|
17
|
+
|
|
18
|
+
On a real tool page: raw HTML 97,944 tokens, a generic converter 4,618, a
|
|
19
|
+
refined file 1,695.
|
|
20
|
+
|
|
21
|
+
**Start here:** the onboarding guide at <https://relvehq.com/agent-ready>
|
|
22
|
+
(every stack, the WordPress plugin download, and how to test it).
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- Node.js 20 or newer
|
|
27
|
+
- For the Next.js adapter: Next.js 13.4+ with the App Router
|
|
28
|
+
- Anything else: the core is plain `Request` / `Response` (see "Other frameworks")
|
|
29
|
+
|
|
30
|
+
## Quick start: one command
|
|
31
|
+
|
|
32
|
+
In your project's root:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
npx @relvehq/agent-ready init
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It detects Next.js, Node servers and WordPress, and sets up the one it finds:
|
|
39
|
+
|
|
40
|
+
| It finds | It does |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `app/` or `src/app/` and `next` in `package.json` | writes the Next.js files (below) |
|
|
43
|
+
| `wp-config.php` or `wp-content/` | copies the bundled plugin to `wp-content/plugins/relve-agent-ready/`, then tells you to activate it and tick Enabled on Settings > Agent Ready (an existing copy is kept unless you add `--force`) |
|
|
44
|
+
| `express`, `connect`, `polka`, `fastify`, `@nestjs/core`, `h3` or `nitropack` in `package.json` | writes nothing; prints the exact lines for that framework and the env vars |
|
|
45
|
+
| none of these | prints what it looked for and the guide's URL, and exits 1 |
|
|
46
|
+
|
|
47
|
+
`--stack next|node|wordpress` skips detection; `--dry-run` shows the plan and
|
|
48
|
+
writes nothing. Step-by-step for every stack: [SETUP.md](./SETUP.md).
|
|
49
|
+
|
|
50
|
+
### Next.js
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
npm install @relvehq/agent-ready
|
|
54
|
+
npx agent-ready init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`init` looks at your project (`app/` or `src/app/`, TypeScript or JavaScript)
|
|
58
|
+
and writes:
|
|
59
|
+
|
|
60
|
+
| File | What it holds |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `agent-ready.config.ts` | `export default createAgentReady()`, smart defaults |
|
|
63
|
+
| `middleware.ts` | `export default withAgentReady(agentReady)` and the matcher (only when you have no middleware yet) |
|
|
64
|
+
| `app/%5F%5Fmd/[[...path]]/route.ts` | the internal route that builds the Markdown (`%5F` is `_`) |
|
|
65
|
+
| `.env.local` | `AGENT_READY_ENABLED=1` and `NEXT_PUBLIC_SITE_URL=http://localhost:3000` |
|
|
66
|
+
|
|
67
|
+
It never edits a file you already have. If you have a middleware, it prints
|
|
68
|
+
the two lines to add:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { withAgentReady } from "@relvehq/agent-ready/next";
|
|
72
|
+
import agentReady from "./agent-ready.config";
|
|
73
|
+
export default withAgentReady(agentReady, yourMiddleware);
|
|
74
|
+
// and add to your matcher: "/((?!_next/).+\\.md)", "/llms.txt"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Running `init` again changes nothing; `--dry-run` shows the plan.
|
|
78
|
+
|
|
79
|
+
Check it with the dev server running:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
curl -i -H "Accept: text/markdown" http://localhost:3000/
|
|
83
|
+
curl -i http://localhost:3000/index.md
|
|
84
|
+
curl -i http://localhost:3000/llms.txt
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
In production set `AGENT_READY_ENABLED=1` and `NEXT_PUBLIC_SITE_URL=https://your-site.com`
|
|
88
|
+
on your host. Without a site URL the package stays off (it never fails your build).
|
|
89
|
+
|
|
90
|
+
### Node server and WordPress
|
|
91
|
+
|
|
92
|
+
For a Node server, `init` prints the lines for your framework (Express,
|
|
93
|
+
Connect, Polka, Nest: `app.use(...)`; Fastify through `@fastify/middie`;
|
|
94
|
+
Nitro and h3 through `fromNodeMiddleware`), and the two env vars:
|
|
95
|
+
`AGENT_READY_ENABLED=1` and `SITE_URL=https://your-site.com`. See "Other
|
|
96
|
+
frameworks" below. For WordPress, the plugin ships inside this package
|
|
97
|
+
(without its tests), so `init` needs no download.
|
|
98
|
+
|
|
99
|
+
### What `createAgentReady()` works out on its own
|
|
100
|
+
|
|
101
|
+
| Setting | Default |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `site` | the first set of `NEXT_PUBLIC_SITE_URL`, `SITE_URL`, `NEXT_PUBLIC_APP_URL`, `URL` (Netlify), `VERCEL_PROJECT_PRODUCTION_URL`, `VERCEL_URL` |
|
|
104
|
+
| `enabled` | `AGENT_READY_ENABLED` is `1` or `true` |
|
|
105
|
+
| `exclude` | `/api`, `/_next`, auth and admin paths, plus common private pages (account, checkout, cart, dashboard, settings, billing…) and yours; `excludeCommon: false` drops the common list |
|
|
106
|
+
| `llms` | `/llms.txt` built from your `sitemap.xml`; `llms: false` for none |
|
|
107
|
+
| `onHit` | sends each visit to a dashboard when `AGENT_READY_KEY` and `AGENT_READY_ENDPOINT` are set |
|
|
108
|
+
|
|
109
|
+
Anything you pass wins:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
export default createAgentReady({
|
|
113
|
+
exclude: ["/members"],
|
|
114
|
+
templates: { "/blog/:slug": async ({ params }) => renderPostMarkdown(params.slug) },
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## How an agent asks
|
|
119
|
+
|
|
120
|
+
| Ask | Example |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `Accept` header | `Accept: text/markdown`, preferred over (or tied with) `text/html` |
|
|
123
|
+
| `.md` URL | `/pricing.md`, `/index.md` for `/` |
|
|
124
|
+
| query | `/pricing?format=md` |
|
|
125
|
+
|
|
126
|
+
A browser's `Accept`, a bare `*/*`, or `text/markdown` with a lower q-value
|
|
127
|
+
than `text/html` is not a Markdown request. The user agent is never used to
|
|
128
|
+
choose what to serve: that would be cloaking.
|
|
129
|
+
|
|
130
|
+
## How it works
|
|
131
|
+
|
|
132
|
+
1. **Detect** (middleware, Edge): is this a Markdown request? If not, nothing changes.
|
|
133
|
+
2. **Rewrite** to the internal route `/__md/<path>`; the public URL stays the same.
|
|
134
|
+
3. **Resolve** (Node route), first hit wins:
|
|
135
|
+
1. a **template** for the route (`"/blog/:slug"`), written from your data
|
|
136
|
+
2. a **stored** file (`store.get(path)`), e.g. one written by `refine`
|
|
137
|
+
3. **convert**: fetch the page's own HTML (public, no cookies) and turn its
|
|
138
|
+
main content into Markdown (Readability + turndown, GFM tables). Under 200
|
|
139
|
+
characters of real text is discarded.
|
|
140
|
+
4. nothing usable: an `Accept` request gets the normal HTML page, a `.md`
|
|
141
|
+
request gets a 404
|
|
142
|
+
4. **Enrich**: YAML front matter (title, canonical, source), facts from JSON-LD, token count.
|
|
143
|
+
5. **Respond**:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Content-Type: text/markdown; charset=utf-8
|
|
147
|
+
Vary: Accept
|
|
148
|
+
Link: <https://your-site.com/pricing>; rel="canonical"
|
|
149
|
+
X-Robots-Tag: noindex (search engines keep indexing the HTML page)
|
|
150
|
+
x-markdown-tokens: 314
|
|
151
|
+
ETag: W/"…" (If-None-Match → 304)
|
|
152
|
+
Cache-Control: see "Caching"
|
|
153
|
+
x-agent-ready-source: native | stored | convert
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
6. **Measure**: one `HitEvent` per request to `onHit`, fire-and-forget.
|
|
157
|
+
|
|
158
|
+
## Caching behind a CDN
|
|
159
|
+
|
|
160
|
+
Most CDNs (CloudFront included) don't vary their cache on `Accept`, so:
|
|
161
|
+
|
|
162
|
+
- Responses negotiated by `Accept` use `negotiatedCacheControl`, default
|
|
163
|
+
`private, max-age=300`. A shared cache never stores them, so a browser is
|
|
164
|
+
never served Markdown.
|
|
165
|
+
- `.md`, `?format=md` and `llms.txt` are their own URLs and use `cacheControl`,
|
|
166
|
+
default `public, s-maxage=300, stale-while-revalidate=86400`.
|
|
167
|
+
- If the CDN already has the HTML page cached, an `Accept` request may get that
|
|
168
|
+
HTML. Safe, just not Markdown. `.md` URLs always work; reliable negotiation
|
|
169
|
+
needs `Accept` in the CDN cache key.
|
|
170
|
+
|
|
171
|
+
## Refine: better Markdown with your own OpenAI key
|
|
172
|
+
|
|
173
|
+
One command, run from your project root with `OPENAI_API_KEY` in `.env.local`,
|
|
174
|
+
`.env` or the shell:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
npx agent-ready refine --site https://your-site.com --sitemap --dry-run
|
|
178
|
+
npx agent-ready refine --site https://your-site.com --sitemap
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
For each page the command fetches the HTML itself and sends it to the Relve
|
|
182
|
+
API (`relvehq.com`) with your key in a header. Relve's prompt runs on Relve's
|
|
183
|
+
server: it extracts the page, calls OpenAI with your key, checks the result
|
|
184
|
+
(every number and URL must be on the page; one retry), and returns the
|
|
185
|
+
Markdown. The command saves `<out>/<path>.md` plus `<out>/<path>.json`
|
|
186
|
+
(default out: `.agent-ready/md`).
|
|
187
|
+
|
|
188
|
+
- **Cost:** your own OpenAI usage, one model call per changed page (roughly
|
|
189
|
+
a few thousand tokens each with the default `gpt-4o-mini`). Relve charges nothing.
|
|
190
|
+
- **Your key:** used for that call only. Relve does not store or log it, and
|
|
191
|
+
it is never written to the output files.
|
|
192
|
+
- **Re-run when content changes.** Each saved `.json` holds the page's
|
|
193
|
+
fingerprint; it is sent along, and an unchanged page comes back as
|
|
194
|
+
`unchanged` with no model call (free). `--force` rewrites everything.
|
|
195
|
+
- **Optional in CI or deploy:** run the command before `next build` (with
|
|
196
|
+
`OPENAI_API_KEY` as a secret) and commit or ship `.agent-ready/md`.
|
|
197
|
+
|
|
198
|
+
| Option | |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `--sitemap` / `--paths /a,/b` | which pages (sitemap at `<site>/sitemap.xml`) |
|
|
201
|
+
| `--model` | `gpt-4o-mini` (default, fastest), `gpt-4o`, `gpt-4.1`, `gpt-4.1-mini` |
|
|
202
|
+
| `--site-name` | your brand name, used in the documents |
|
|
203
|
+
| `--out`, `--limit`, `--concurrency` (2), `--force`, `--dry-run` | `--dry-run` lists the pages: no API call, nothing written |
|
|
204
|
+
| `AGENT_READY_REFINE_ENDPOINT` | another API URL (testing) |
|
|
205
|
+
|
|
206
|
+
The run ends with `written / unchanged / rejected / errors` and the token
|
|
207
|
+
total. Rejected and failed pages are listed with their code (for example
|
|
208
|
+
`too_little_text`) and nothing is saved for them; the exit code is then 1.
|
|
209
|
+
If OpenAI rejects the key or your account is out of quota, the run stops at
|
|
210
|
+
the first page and says so.
|
|
211
|
+
|
|
212
|
+
Serve the files from the route file (`fileStore` is Node only, so keep it
|
|
213
|
+
out of `agent-ready.config.ts`, which the Edge middleware imports):
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
// app/%5F%5Fmd/[[...path]]/route.ts
|
|
217
|
+
import { createMarkdownRoute } from "@relvehq/agent-ready/next/route";
|
|
218
|
+
import { fileStore } from "@relvehq/agent-ready/refine/file-store";
|
|
219
|
+
import agentReady from "../../../agent-ready.config";
|
|
220
|
+
export const { GET, HEAD } = createMarkdownRoute({ ...agentReady, store: fileStore(".agent-ready/md") });
|
|
221
|
+
export const runtime = "nodejs";
|
|
222
|
+
export const dynamic = "force-dynamic";
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
On serverless hosts (Vercel, Amplify) the folder must be bundled with the
|
|
226
|
+
route (`outputFileTracingIncludes`); see [SETUP.md](./SETUP.md).
|
|
227
|
+
|
|
228
|
+
**The check** rejects a file when a number or URL in it is not on the page, a
|
|
229
|
+
required section is missing, it has more or fewer than one H1, HTML tags, a
|
|
230
|
+
wrong fingerprint, or it is over the token budget. It cannot catch a reworded
|
|
231
|
+
claim, so read a sample before you switch on.
|
|
232
|
+
|
|
233
|
+
**Advanced: your own prompts.** The package ships no prompt. With
|
|
234
|
+
`--prompts <dir>` (several: `a,b`) or the `AGENT_READY_PROMPTS` variable
|
|
235
|
+
(`.env.local`, `.env` or the shell), `refine` runs your prompt files on your
|
|
236
|
+
machine instead of calling the Relve API, with `OPENAI_API_KEY` (default
|
|
237
|
+
model `gpt-4o`) or `ANTHROPIC_API_KEY` (default `claude-opus-5-5`);
|
|
238
|
+
`AGENT_READY_MODEL` picks another model. The steps are the same: fetch,
|
|
239
|
+
extract, skip unchanged, fill the prompt, one model call, check, one retry,
|
|
240
|
+
save. A prompt file is Markdown with `## SYSTEM`, `## USER`
|
|
241
|
+
(`{{PAGE_URL}}`, `{{PAGE_TEXT}}`, `{{PAGE_LINKS}}`, `{{JSON_LD}}`,
|
|
242
|
+
`{{SOURCE_HASH}}`) and a `## Settings` table (`page_type`, `version`,
|
|
243
|
+
`required_sections`, `token_budget`). A `page_type` of `page` takes every
|
|
244
|
+
path no other prompt claims; for it the code guesses the page's kind from its
|
|
245
|
+
URL and JSON-LD (home, product, pricing, article, docs, listing, event, about,
|
|
246
|
+
contact, legal, other) and passes the guess as `{{PAGE_KIND_HINT}}`.
|
|
247
|
+
|
|
248
|
+
## Proof
|
|
249
|
+
|
|
250
|
+
### Free checker
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
npx agent-ready check https://any-site.com/pricing
|
|
254
|
+
npx agent-ready check any-site.com --json
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Read-only. Scores the site out of 100 (A to F): Markdown for `Accept` (25),
|
|
258
|
+
a `.md` URL (15), `/llms.txt` (15), robots.txt letting AI answer bots in (15),
|
|
259
|
+
a sitemap (10), JSON-LD (10), `Vary: Accept` (5), a canonical (5). Each failing
|
|
260
|
+
check says what to do, and it compares the tokens an agent reads today with
|
|
261
|
+
what agent-ready would serve. In code: `auditSite(url)`.
|
|
262
|
+
|
|
263
|
+
### Dashboard
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
// agent-ready.config.ts
|
|
267
|
+
import { createAgentReady, memoryHitStore } from "@relvehq/agent-ready";
|
|
268
|
+
export const hits = memoryHitStore();
|
|
269
|
+
export default createAgentReady({ hits });
|
|
270
|
+
|
|
271
|
+
// app/agent-ready-dashboard/route.ts
|
|
272
|
+
import { createDashboardRoute } from "@relvehq/agent-ready/next/dashboard";
|
|
273
|
+
import { hits } from "../../agent-ready.config";
|
|
274
|
+
export const { GET } = createDashboardRoute({ store: hits, site: "your-site.com" });
|
|
275
|
+
export const dynamic = "force-dynamic";
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Open `/agent-ready-dashboard?key=<AGENT_READY_DASHBOARD_KEY>` (add
|
|
279
|
+
`&format=json` for the data, `&days=7` for a shorter window). Without a key
|
|
280
|
+
configured the route answers 404. It shows visits per day, who is reading (AI
|
|
281
|
+
assistants, AI search, training bots, search engines), top pages, how agents
|
|
282
|
+
asked, where the Markdown came from, tokens served and response time.
|
|
283
|
+
|
|
284
|
+
A `HitStore` is two methods, `add` and `list`. `memoryHitStore()` suits a
|
|
285
|
+
long-running server; `jsonlHitStore(file)` (`@relvehq/agent-ready/proof/jsonl`)
|
|
286
|
+
writes a log that `npx agent-ready stats --log <file>` summarises. On
|
|
287
|
+
serverless hosts (Vercel, Amplify) memory and local files don't last between
|
|
288
|
+
requests: implement `HitStore` on your database.
|
|
289
|
+
|
|
290
|
+
## Other frameworks
|
|
291
|
+
|
|
292
|
+
Express, Connect, Polka, Fastify (via `@fastify/middie`) or a plain `http`
|
|
293
|
+
server: one middleware. Mount it before your static files and routes:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
import express from "express";
|
|
297
|
+
import { createAgentReady } from "@relvehq/agent-ready";
|
|
298
|
+
import { agentReadyNode } from "@relvehq/agent-ready/node";
|
|
299
|
+
|
|
300
|
+
const app = express();
|
|
301
|
+
app.use(agentReadyNode(createAgentReady({ site: "https://your-site.com" })));
|
|
302
|
+
// app.use(express.static("public")); your routes...
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
It answers Markdown requests and calls `next()` for everything else (and for
|
|
306
|
+
an `Accept` request when no Markdown is available, so the page's HTML is
|
|
307
|
+
served). Plain `http`: `http.createServer((req, res) => md(req, res, () => app(req, res)))`.
|
|
308
|
+
|
|
309
|
+
On other runtimes (Bun, Deno, Workers, Hono…) the core uses only `Request` and
|
|
310
|
+
`Response`. Detect, enrich and respond run anywhere; `resolveMarkdown` (its
|
|
311
|
+
convert step) needs Node, so on Edge-only runtimes use templates and a store
|
|
312
|
+
with `fallback: "none"`:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import { defineAgentReady, wantsMarkdown, enrich, markdownResponse } from "@relvehq/agent-ready";
|
|
316
|
+
import { resolveMarkdown } from "@relvehq/agent-ready/core/resolve"; // Node only
|
|
317
|
+
|
|
318
|
+
const cfg = defineAgentReady({ site: "https://your-site.com", enabled: true });
|
|
319
|
+
const d = wantsMarkdown(request);
|
|
320
|
+
if (d.markdown) {
|
|
321
|
+
const r = await resolveMarkdown(cfg, { path: d.path, search: d.search, request });
|
|
322
|
+
if (r.doc) {
|
|
323
|
+
const { body, tokens } = enrich(r.doc, { canonical: cfg.site + d.path, sourceUrl: r.sourceUrl, source: r.source! });
|
|
324
|
+
return markdownResponse(body, { request, canonical: cfg.site + d.path, tokens, cacheControl: cfg.cacheControl });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
`@relvehq/agent-ready` and `@relvehq/agent-ready/next` are Edge-safe.
|
|
330
|
+
`/node`, `/next/route`, `/core/resolve`, `/core/convert` and `/refine/*` need Node.
|
|
331
|
+
|
|
332
|
+
## Config reference (`defineAgentReady` / `createAgentReady`)
|
|
333
|
+
|
|
334
|
+
| Key | Default | Notes |
|
|
335
|
+
|---|---|---|
|
|
336
|
+
| `site` | required (`createAgentReady`: from env) | public origin, for canonicals and absolute links |
|
|
337
|
+
| `enabled` | `false` | boolean or `(request) => boolean` |
|
|
338
|
+
| `exclude` | `[]` | path prefixes or RegExps, added to the always-excluded list |
|
|
339
|
+
| `templates` | `{}` | `{ "/blog/:slug": fn }`, first matching pattern wins |
|
|
340
|
+
| `store` | `null` | `{ get(path) }` |
|
|
341
|
+
| `fallback` | `"convert"` | `"none"` serves only templates and stored files |
|
|
342
|
+
| `cacheControl` | `public, s-maxage=300, stale-while-revalidate=86400` | `.md`, `?format=md`, llms.txt |
|
|
343
|
+
| `negotiatedCacheControl` | `private, max-age=300` | `Accept` requests |
|
|
344
|
+
| `llms` | `null` (`createAgentReady`: from the sitemap) | `{ path, title, summary, details, entries }` |
|
|
345
|
+
| `onHit` | `null` | `(HitEvent) => void` |
|
|
346
|
+
| `internalPrefix` | `/__md` | rewrite target |
|
|
347
|
+
| `fetchTimeoutMs` | `8000` | page fetch for convert |
|
|
348
|
+
| `minChars` | `200` | quality gate for convert |
|
|
349
|
+
|
|
350
|
+
## Commands
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
agent-ready init [--stack next|node|wordpress] [--dry-run] [--force] [--cwd <dir>]
|
|
354
|
+
agent-ready check <url> [--json]
|
|
355
|
+
agent-ready refine --site <origin> (--paths /a,/b | --sitemap) [--model <id>] [--site-name <name>]
|
|
356
|
+
[--out <dir>] [--limit <n>] [--force] [--concurrency <n>] [--dry-run]
|
|
357
|
+
[--prompts <dir>] (advanced: your own prompts, run locally)
|
|
358
|
+
agent-ready stats --log <hits.jsonl> [--days <n>] [--json]
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## License
|
|
362
|
+
|
|
363
|
+
MIT © [Relve](https://relvehq.com). Built by the team behind Relve, the AI
|
|
364
|
+
tools and market intelligence platform.
|