@seoagent-official/seoagent 1.85.0 → 1.85.1
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/index.js +236 -160
- package/package.json +1 -1
- package/skills/references/audit-checks.md +17 -0
- package/skills/references/open-knowledge-format.md +27 -5
- package/skills/references/sitemaps.md +41 -22
- package/skills/seoagent.md +19 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seoagent-official/seoagent",
|
|
3
|
-
"version": "1.85.
|
|
3
|
+
"version": "1.85.1",
|
|
4
4
|
"description": "The persistent AI SEO agent for Claude Code. Audits, keyword strategy, briefs, articles, real product screenshots from your repo, and the autopilot loop (cloud detects → CLI executes → ack closes) — other SEO tools write the prompt, SEOAgent runs it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -257,6 +257,23 @@ Check: page has primary keyword in title/H1 but no paragraph in the first 200 wo
|
|
|
257
257
|
Severity: `medium`
|
|
258
258
|
Recommendation: "Lead with a definition or direct answer in the first paragraph (40-80 words) so AI search engines can extract it."
|
|
259
259
|
|
|
260
|
+
### `llms_txt_missing`
|
|
261
|
+
Check: `WebFetch https://{domain}/llms.txt`. It fails the check if it 404s, or returns something that isn't markdown starting with an `#` H1 (a soft-404 / SPA shell).
|
|
262
|
+
Severity: `medium`
|
|
263
|
+
Recommendation: "Your site serves no `llms.txt` — the markdown map ChatGPT, Claude, Perplexity and AI Overviews read to work out what this site is. `seoagent llms` generates one from your page inventory, published articles and crawl evidence, and publishes it to your static dir; every `seoagent sync` keeps it current after that."
|
|
264
|
+
> Fixing this is one command. Run `seoagent llms` — do not hand-write the file, and do not tell the user to; a hand-written one goes stale the moment they publish anything, which is the state this check exists to catch.
|
|
265
|
+
|
|
266
|
+
### `okf_bundle_missing`
|
|
267
|
+
Check: `WebFetch https://{domain}/.well-known/okf/index.md`, then `https://{domain}/okf/index.md`. It passes only if one of them returns markdown whose YAML frontmatter carries a `type:` field. A 200 that renders your app shell is a soft-404 — that is a FAIL, not a pass.
|
|
268
|
+
Severity: `medium` (`low` for a purely local/internal site with no answer-engine ambitions)
|
|
269
|
+
Recommendation: "Your site publishes no Open Knowledge Format bundle. OKF is Google's format for describing an organization to AI agents: a directory of markdown files answer engines can read wholesale instead of guessing from scraped pages. `.seoagent/okf/` is already scaffolded — fill it (see `references/open-knowledge-format.md`) and `seoagent sync` publishes it to `/.well-known/okf/` automatically."
|
|
270
|
+
> **`.seoagent/okf/` existing is NOT a pass.** The check is about what the live site SERVES. A bundle that only exists in `.seoagent/` is invisible to every crawler — that gap is the whole reason this check exists.
|
|
271
|
+
|
|
272
|
+
### `ai_files_unpublished`
|
|
273
|
+
Check: `.seoagent/okf/` has real content (not the scaffold placeholders) but `{domain}/.well-known/okf/index.md` 404s — i.e. the bundle was written and never reached the live site.
|
|
274
|
+
Severity: `high` (the work is done and earning nothing)
|
|
275
|
+
Recommendation: "The OKF bundle exists in `.seoagent/okf/` but isn't served. Check `public_dir:` in `.seoagent/project.md` points at the directory your framework serves (`public` for Next.js/Vite/Astro, `static` for SvelteKit/Gatsby/Hugo), run `seoagent okf publish`, and commit + deploy the result."
|
|
276
|
+
|
|
260
277
|
### `faq_section_missing_on_pillar`
|
|
261
278
|
Check: page is page_type=pillar but has no `<h2>` containing "FAQ" or "Frequently Asked Questions".
|
|
262
279
|
Severity: `low`
|
|
@@ -6,9 +6,20 @@ OKF is an open standard Google published in 2026 (spec + reference code at `gith
|
|
|
6
6
|
|
|
7
7
|
This file is the protocol for generating and maintaining a site's OKF bundle. The deterministic parts (scaffold + validate) are CLI commands; **you** write the bundle content by mapping `.seoagent/` artifacts into OKF files.
|
|
8
8
|
|
|
9
|
-
## Where the bundle lives
|
|
9
|
+
## Where the bundle lives — source vs. served
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Two locations, and confusing them is how this work becomes invisible:
|
|
12
|
+
|
|
13
|
+
| | Path | Who writes it |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| **Source** | `.seoagent/okf/` | you (the skill), scaffolded by `seoagent init` |
|
|
16
|
+
| **Served** | `<public_dir>/.well-known/okf/` → `https://site/.well-known/okf/index.md` | `seoagent sync`, automatically |
|
|
17
|
+
|
|
18
|
+
Crawlers only ever read the SERVED copy. `seoagent sync` mirrors source → served on every run, so you never have to copy files by hand — but it publishes **only** a bundle that is (a) filled in, with no scaffold placeholders left, and (b) clean under `seoagent okf validate`. Serving skeleton or broken markdown to an answer engine is worse than serving nothing, so those two gates are hard.
|
|
19
|
+
|
|
20
|
+
`public_dir:` in `.seoagent/project.md` decides where "served" is; `init` auto-detects it (`public` for Next.js/Vite/Astro, `static` for SvelteKit/Gatsby/Hugo). If sync says it couldn't find one, set it by hand.
|
|
21
|
+
|
|
22
|
+
**The user still has to commit and deploy the published files.** Say so explicitly when you finish a bundle — it is the one step neither you nor the CLI can do.
|
|
12
23
|
|
|
13
24
|
## Frontmatter rules
|
|
14
25
|
|
|
@@ -51,14 +62,14 @@ Cross-link concepts with **relative markdown links only** (`[Pricing](concepts/p
|
|
|
51
62
|
|
|
52
63
|
## Generation protocol
|
|
53
64
|
|
|
54
|
-
1.
|
|
65
|
+
1. `.seoagent/okf/` already exists (`seoagent init` scaffolds it). For an older project, `seoagent okf scaffold` creates the skeleton — it never overwrites existing files.
|
|
55
66
|
2. Fill `index.md` from `.seoagent/context.md` and `project.md`: what the business does, who it serves, then a linked list of the concept / FAQ / article files.
|
|
56
67
|
3. For each keyword cluster in `.seoagent/strategy/clusters/`, write a `concepts/<slug>.md` (`type: Concept` or `Topic`) capturing the definitive, factual explanation — not marketing fluff. Stats, definitions, and comparisons are what AI cites.
|
|
57
68
|
4. For each clear question the business answers, write a `faqs/<slug>.md` (`type: FAQ`): the question as the title, a tight factual answer in the body.
|
|
58
69
|
5. For each published article in `.seoagent/content/`, write `articles/<slug>.md` (`type: Article`) with `resource:` set to the live URL and a 2–4 sentence factual summary; cross-link related concepts.
|
|
59
70
|
6. Add a dated entry to `log.md`.
|
|
60
|
-
7. Run `seoagent okf validate` and fix every error (missing `type`, bad `timestamp`, broken link) before finishing.
|
|
61
|
-
8.
|
|
71
|
+
7. Run `seoagent okf validate` and fix every error (missing `type`, bad `timestamp`, broken link) before finishing. **A bundle with errors is never published.**
|
|
72
|
+
8. Run `seoagent sync`. It pushes the bundle to the cloud dashboard AND publishes it to `<public_dir>/.well-known/okf/`. Tell the user to commit + deploy those files.
|
|
62
73
|
|
|
63
74
|
## Quality bar
|
|
64
75
|
|
|
@@ -67,8 +78,19 @@ Cross-link concepts with **relative markdown links only** (`[Pricing](concepts/p
|
|
|
67
78
|
- Keep `resource:` URLs canonical and live — they are how an agent verifies and cites you.
|
|
68
79
|
- Regenerate when content changes so the bundle never drifts from reality.
|
|
69
80
|
|
|
81
|
+
## llms.txt — the other half of the layer
|
|
82
|
+
|
|
83
|
+
`llms.txt` is a markdown map of the site for LLMs, served at `/llms.txt`. It is the cheaper, blunter companion to the OKF bundle: an H1 with the site name, a one-line summary, then `##` sections of links with a short description each.
|
|
84
|
+
|
|
85
|
+
**Do not hand-write it.** `seoagent llms` generates it from `.seoagent/pages.md`, `.seoagent/content/` (published articles only — a draft link would be dead), `.seoagent/audit/evidence.md` (real crawled titles + meta descriptions) and `.seoagent/context.md`, writes the source to `.seoagent/llms.md`, and publishes `<public_dir>/llms.txt`. Every `seoagent sync` regenerates it, so it cannot go stale after a publish — which is exactly how hand-written ones die.
|
|
86
|
+
|
|
87
|
+
**If the project already serves `/llms.txt` from a route** (`app/llms.txt/route.ts`, `src/pages/llms.txt.ts`, `src/routes/llms.txt/+server.ts`, …), SEOAgent detects it and publishes nothing: a file in the static dir would shadow that route and silently replace working behaviour. It still writes `.seoagent/llms.md`, so you can compare. Tell the user their route owns the file — they either keep it current themselves, or delete the route to hand ownership to SEOAgent.
|
|
88
|
+
|
|
70
89
|
## CLI commands
|
|
71
90
|
|
|
72
91
|
- `seoagent okf` — status (is a bundle present? how many files?)
|
|
73
92
|
- `seoagent okf scaffold` — create the starter `index.md` + `log.md`
|
|
74
93
|
- `seoagent okf validate` — assert every file has `type`, timestamps are ISO-8601, and all relative links resolve
|
|
94
|
+
- `seoagent okf publish` — copy the bundle into `<public_dir>/.well-known/okf/` on demand
|
|
95
|
+
- `seoagent llms` — generate + publish `llms.txt`
|
|
96
|
+
- `seoagent sync` — does the publish half of both, automatically, every time
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sitemap Protocol
|
|
2
2
|
|
|
3
|
-
A sitemap (`/sitemap.xml`) is the list of URLs you want search engines to crawl and index, with optional `lastmod` dates so crawlers prioritize what changed. A missing, stale, or broken sitemap means new pages get discovered slowly or not at all — and a sitemap that leaks private routes (`/admin`, `/login`, `/api`) wastes crawl budget and can surface junk in search.
|
|
3
|
+
A sitemap (`/sitemap.xml`) is the list of URLs you want search engines to crawl and index, with optional `lastmod` dates so crawlers prioritize what changed. `lastmod` is optional on purpose — see the rule below. A missing, stale, or broken sitemap means new pages get discovered slowly or not at all — and a sitemap that leaks private routes (`/admin`, `/login`, `/api`) wastes crawl budget and can surface junk in search.
|
|
4
4
|
|
|
5
5
|
**Generation belongs to you (the agent); validation belongs to the CLI.** You edit the site's sitemap generator to keep it correct; `seoagent sitemap` fetches the live sitemap and reports problems. This mirrors the OKF split (you write, CLI validates).
|
|
6
6
|
|
|
@@ -8,11 +8,11 @@ A sitemap (`/sitemap.xml`) is the list of URLs you want search engines to crawl
|
|
|
8
8
|
|
|
9
9
|
Don't conflate these — they're three different files for three different readers:
|
|
10
10
|
|
|
11
|
-
| Artifact
|
|
12
|
-
|
|
13
|
-
| **`sitemap.xml`**
|
|
14
|
-
| **`llms.txt`**
|
|
15
|
-
| **OKF bundle** (`/.well-known/okf/`) | AI agents (AEO/GEO)
|
|
11
|
+
| Artifact | Who reads it | What it says |
|
|
12
|
+
| ------------------------------------ | ------------------------------ | ------------------------------------------------------------------------------------------- |
|
|
13
|
+
| **`sitemap.xml`** | Search crawlers (Google, Bing) | "Here are all my pages + when they changed" |
|
|
14
|
+
| **`llms.txt`** | LLMs fetching the site | "Here's a clean index of my content" |
|
|
15
|
+
| **OKF bundle** (`/.well-known/okf/`) | AI agents (AEO/GEO) | "Here's structured knowledge about my business" — see `references/open-knowledge-format.md` |
|
|
16
16
|
|
|
17
17
|
The sitemap is about **page discovery for search engines**. OKF is a separate AEO/GEO play (Phase 5). Maintain the sitemap as part of normal SEO; treat OKF as an additional, optional artifact.
|
|
18
18
|
|
|
@@ -20,21 +20,21 @@ The sitemap is about **page discovery for search engines**. OKF is a separate AE
|
|
|
20
20
|
|
|
21
21
|
Figure out how the site produces `/sitemap.xml` before changing anything:
|
|
22
22
|
|
|
23
|
-
| Signal in the repo
|
|
24
|
-
|
|
25
|
-
| `app/sitemap.ts` / `app/sitemap.js`
|
|
26
|
-
| `next-sitemap.config.js` + `next-sitemap` dep | **next-sitemap** (build-time)
|
|
27
|
-
| `@astrojs/sitemap` in `astro.config.*`
|
|
28
|
-
| `public/sitemap.xml` or `static/sitemap.xml`
|
|
29
|
-
| Hugo / Jekyll / 11ty
|
|
30
|
-
| none of the above
|
|
23
|
+
| Signal in the repo | Generator |
|
|
24
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
25
|
+
| `app/sitemap.ts` / `app/sitemap.js` | **Next.js dynamic** (App Router) — served at `/sitemap.xml`, no file on disk |
|
|
26
|
+
| `next-sitemap.config.js` + `next-sitemap` dep | **next-sitemap** (build-time) |
|
|
27
|
+
| `@astrojs/sitemap` in `astro.config.*` | **Astro integration** (build-time) |
|
|
28
|
+
| `public/sitemap.xml` or `static/sitemap.xml` | **Static file** (hand-maintained) |
|
|
29
|
+
| Hugo / Jekyll / 11ty | Framework default (usually automatic) |
|
|
30
|
+
| none of the above | **No sitemap** — create one |
|
|
31
31
|
|
|
32
32
|
> **Critical:** a dynamic generator (`app/sitemap.ts`) serves `/sitemap.xml` with **no file in the repo**. Never conclude "there's no sitemap" from a missing file — always check the **live** URL (`seoagent sitemap` does this). Judging by committed files alone is exactly the bug that makes a complete sitemap look empty.
|
|
33
33
|
|
|
34
34
|
## Step 2 — Keep it current when you publish
|
|
35
35
|
|
|
36
36
|
- **Dynamic / framework generators** (Next `app/sitemap.ts`, next-sitemap, Astro): usually auto-include new repo content. After adding a page, confirm it appears (`seoagent sitemap`). If the generator enumerates a content dir, make sure your new file lands where it scans. If it hard-codes a `staticPages` list, **add the new URL to that list**.
|
|
37
|
-
- **Static `public/sitemap.xml`**: add a `<url><loc>…</loc
|
|
37
|
+
- **Static `public/sitemap.xml`**: add a `<url><loc>…</loc></url>` entry by hand for every new page (add `<lastmod>` only if you will keep it truthful).
|
|
38
38
|
- **No generator yet**: scaffold one. For Next.js App Router, an `app/sitemap.ts` that returns static routes + maps your content dir is the lowest-friction option (it's the same pattern this repo uses — see `apps/web/src/app/sitemap.ts`).
|
|
39
39
|
|
|
40
40
|
When you publish an article (Phase 4) or a programmatic batch, **ensuring the sitemap covers the new URL is part of publishing**, not a separate task.
|
|
@@ -49,19 +49,38 @@ seoagent sitemap --json # machine-readable (for scripting)
|
|
|
49
49
|
|
|
50
50
|
It reports, and you fix:
|
|
51
51
|
|
|
52
|
-
| Finding
|
|
53
|
-
|
|
54
|
-
| **error: HTTP 4xx/5xx / unreachable**
|
|
55
|
-
| **error: not valid XML / zero URLs**
|
|
56
|
-
| **warning: private URLs leaked**
|
|
57
|
-
| **warning: public pages missing**
|
|
58
|
-
| **
|
|
52
|
+
| Finding | Meaning | Fix |
|
|
53
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
54
|
+
| **error: HTTP 4xx/5xx / unreachable** | Google can't fetch it | Make `/sitemap.xml` serve 200 (deploy the generator; check the route) |
|
|
55
|
+
| **error: not valid XML / zero URLs** | Soft-empty sitemap | Fix the generator output |
|
|
56
|
+
| **warning: private URLs leaked** | `/admin`, `/login`, `/api`, etc. in the sitemap | Remove auth/admin/api routes from the generator's URL list |
|
|
57
|
+
| **warning: public pages missing** | Repo routes/content absent from the sitemap | Add them to the generator |
|
|
58
|
+
| **warning: every URL shares one `<lastmod>`** | The generator stamps its own build time on every entry, so the field carries no information | Emit a real per-page date where you have one; omit `<lastmod>` for the rest |
|
|
59
|
+
| **info: no `<lastmod>`** | Nothing to prioritize on — which is fine | Optional: add a **real** per-page date (CMS `updatedAt`, file mtime). Do not add a bulk date |
|
|
60
|
+
|
|
61
|
+
### The `<lastmod>` rule
|
|
62
|
+
|
|
63
|
+
**Emit `<lastmod>` only where a real content date exists. Omit it everywhere else.**
|
|
64
|
+
|
|
65
|
+
Google treats `lastmod` as a hint it can stop trusting. A generator that writes
|
|
66
|
+
`new Date()` into every entry produces one identical date across the whole file;
|
|
67
|
+
Google reads that as "this sitemap's `lastmod` carries no information" and
|
|
68
|
+
discounts the field **site-wide** — including the pages whose dates are real.
|
|
69
|
+
|
|
70
|
+
- ✅ A CMS `updatedAt` / `published_at`, a file mtime, a git commit date.
|
|
71
|
+
- ❌ `new Date()`, the build time, "today" — on every URL.
|
|
72
|
+
- An omitted `<lastmod>` is a truthful "we don't track that for this page". It
|
|
73
|
+
costs you nothing. A bulk stamp costs you the whole field.
|
|
74
|
+
|
|
75
|
+
Seen in the wild on seoagent.com itself: 85 of 125 URLs carried one identical
|
|
76
|
+
millisecond timestamp — the moment the sitemap was rendered.
|
|
59
77
|
|
|
60
78
|
Run it as part of the **Phase 1 audit** and again **after publishing**.
|
|
61
79
|
|
|
62
80
|
## Step 4 — Submit to Google
|
|
63
81
|
|
|
64
82
|
A sitemap only helps once Google knows about it:
|
|
83
|
+
|
|
65
84
|
- Add `Sitemap: https://{domain}/sitemap.xml` to `robots.txt`.
|
|
66
85
|
- Submit it in Google Search Console → Sitemaps (one-time).
|
|
67
86
|
- **If the user has SEOAgent Cloud with GSC connected, this is automatic** — the cloud resubmits on a schedule (see below). Tell them so they don't do it twice.
|
package/skills/seoagent.md
CHANGED
|
@@ -128,6 +128,7 @@ Offer **once per session per topic**; if declined, drop it and keep working. Nev
|
|
|
128
128
|
- **`cli_new_content`** — autopilot found a content brief with no article written yet. Write + publish the article. Safe (new content).
|
|
129
129
|
- **`cli_content_update`** — autopilot flagged an existing page to revise (declining GSC clicks, low CTR, or stale/thin). Reversible (edits existing content).
|
|
130
130
|
- **`cli_sitemap_update`** — GSC is connected but can't fetch a sitemap at the site's `/sitemap.xml`. Write/refresh the project's sitemap (from the URL list in the file, which includes CMS-hosted articles) so Google can index it. Safe (adds/updates a sitemap).
|
|
131
|
+
- **`cli_ai_files_update`** — the AI-readable file layer (Open Knowledge Format bundle + `llms.txt`) is missing, unmanaged, or stale. These are what ChatGPT, Claude, Perplexity and Google's AI Overviews read to decide what the site is. Scaffold/refresh them **and publish them to the paths crawlers actually fetch** (`/.well-known/okf/`, `/llms.txt`). Safe (adds/updates static files).
|
|
131
132
|
- **`cli_new_landing_page`** — the keyword engine flagged a high-value keyword (`easy_win` or `competitor_gap`) with no page covering it. Write a dedicated landing page targeting it. Safe (new content).
|
|
132
133
|
- **`cli_draft_ready`** — the cloud already **wrote a complete article** (drafted from a brief, or generated during the user's onboarding) and synced it to `.seoagent/content/<slug>.md` in the same pull. Nothing to write — review the draft and place it where this site's content renders. Safe (new content).
|
|
133
134
|
|
|
@@ -187,7 +188,14 @@ Offer **once per session per topic**; if declined, drop it and keep working. Nev
|
|
|
187
188
|
- **Verify with `seoagent sitemap`** once deployed — it should report 200, no private leakage, and the expected URL count.
|
|
188
189
|
- Acknowledge it: `seoagent ack <action_id>` (or `--failed --reason "sitemap already served"` to decline). SEOAgent re-submits the sitemap to GSC on its schedule.
|
|
189
190
|
|
|
190
|
-
7. For each `
|
|
191
|
+
7. For each `cli_ai_files_update-<id>.md` file:
|
|
192
|
+
- `Read` it. The frontmatter has `action_id` and `needs` (e.g. `okf:unmanaged, llms_txt:missing`); the body says what to do per file and lists the site's published pages.
|
|
193
|
+
- **`okf`** — fill `.seoagent/okf/` per `references/open-knowledge-format.md` (it is already scaffolded; `seoagent okf scaffold` covers an older project). **Replace every scaffold placeholder** and make `seoagent okf validate` pass — a placeholder or invalid bundle is deliberately NOT published. Then `seoagent sync` copies it to `<public_dir>/.well-known/okf/` (or `seoagent okf publish` on demand), and **you tell the user to commit + deploy**. `.seoagent/okf/` is the source; crawlers only read `/.well-known/okf/index.md`.
|
|
194
|
+
- **`llms_txt`** — run `seoagent llms`. **Do not hand-write it.** It is generated from `pages.md`, published `content/`, crawl evidence and `context.md`, so every link resolves and it regenerates on every sync instead of going stale after the next publish. If the page inventory is thin, run `seoagent refresh --crawl` first.
|
|
195
|
+
- **Both files must agree with the live site** on pricing, plan names, and positioning. A bundle that contradicts your own pages is worse than none. Cross-check `/pricing` before you write numbers.
|
|
196
|
+
- Show the user the diff, deploy, then acknowledge: `seoagent ack <action_id>` (or `--failed --reason "..."` to decline).
|
|
197
|
+
|
|
198
|
+
8. For each `cli_new_landing_page-<id>.md` file:
|
|
191
199
|
- `Read` it. The frontmatter has `action_id`, `keyword`, `opportunity` (`easy_win` | `competitor_gap`), `volume`, `difficulty`, and `intent`. The body explains why this keyword is worth a page.
|
|
192
200
|
- Cross-reference `.seoagent/keywords.md` for related keywords — they tell you which cluster this page belongs to and which secondary keywords to weave in.
|
|
193
201
|
- Pick an article type from `intent` (commercial/transactional → product or comparison page; informational → guide or pillar). Pick a clean URL slug from `keyword`.
|
|
@@ -196,7 +204,7 @@ Offer **once per session per topic**; if declined, drop it and keep working. Nev
|
|
|
196
204
|
- Publish where this project's content lives (repo `content/` or the connected CMS). Safe (new content) — but still confirm the user wants this specific page before committing.
|
|
197
205
|
- Acknowledge it: `seoagent ack <action_id>` (or `--failed --reason "already covered by /existing-page"` to decline).
|
|
198
206
|
|
|
199
|
-
|
|
207
|
+
9. For each `cli_draft_ready-<id>.md` file:
|
|
200
208
|
- `Read` it. The frontmatter has `action_id`, `article_slug`, `path`, and (when drafted from a brief) `brief_slug`. The draft itself is at `.seoagent/<path>` — pulled in the same sync that delivered this task.
|
|
201
209
|
- **Review the draft** (frontmatter carries title, meta description, status), then place it where this project's content renders: repo-native (mdx_sync) → copy/adapt into the repo's content directory and `seoagent content track` it; CMS → create the entry and track it; cloud-hosted → flip frontmatter `status` to `published` and sync. The inbox file body walks through each strategy.
|
|
202
210
|
- Edit freely before publishing — the `.seoagent` copy is the user's now. Show the user the draft before publishing.
|
|
@@ -480,6 +488,8 @@ A line with neither is invalid output — rewrite it or drop it before respondin
|
|
|
480
488
|
8. **Internal-link pass.** Run the **Internal Link Analysis** below to find orphan pages (no inbound internal links) and fold any orphans into the audit findings (`medium` severity, category internal-linking).
|
|
481
489
|
9. **Indexing-coverage pass (cloud-connected — run whenever `seoagent whoami` shows a login).** Run `seoagent indexing` — it inspects the live sitemap's URLs with Google Search Console URL Inspection (authoritative verdicts, not inference) and writes `.seoagent/audit/indexing.md`. Read that file and fold its findings into the audit per `audit-checks.md` § Indexing Coverage: sitemap URLs Google has NOT indexed (`high`), pages whose indexing is blocked by robots/noindex per GSC (`critical`), Google-chose-a-different-canonical mismatches (`medium`), and a `high` coverage finding when under half the inspected sitemap URLs are indexed. Findings derived from `indexing.md` rows are `Confirmed` (cite `Evidence: indexing.md § <URL>`); URLs its "Not inspected" section lists have NO verdict — never claim anything about them. **If the CLI is logged out** (`seoagent indexing` says login is required), do NOT guess indexing state — and do NOT use `site:` searches as a substitute (they under-report) — state "indexing coverage not verified (needs the free `seoagent login`, which connects Search Console)" in the audit output and move on.
|
|
482
490
|
|
|
491
|
+
10. **AI-readability pass (always — this is the free tier's sharpest finding).** Two files decide whether ChatGPT, Claude, Perplexity and AI Overviews can describe this site accurately: `/llms.txt` and the OKF bundle at `/.well-known/okf/index.md`. WebFetch both and run `llms_txt_missing`, `okf_bundle_missing`, and `ai_files_unpublished` from `audit-checks.md`. Judge what the LIVE SITE SERVES — a bundle sitting in `.seoagent/okf/` that nobody published is a FAIL, and the most common one. Fixing `llms.txt` is a single command (`seoagent llms`); offer to run it in the "What do you want to do?" options rather than describing it.
|
|
492
|
+
|
|
483
493
|
> **If the audit raises any `critical` finding from `upstream_dependency_unreachable` or `page_renders_empty`**, do not proceed to Phase 2. Jump to the **Publishing Target Decision** section below — every keyword, brief, and article generated against a broken publishing path is wasted work.
|
|
484
494
|
|
|
485
495
|
### Output: `.seoagent/audit/latest.md`
|
|
@@ -951,10 +961,11 @@ When the user asks to "publish an OKF bundle", "make my site AI-readable", "get
|
|
|
951
961
|
|
|
952
962
|
**Read `references/open-knowledge-format.md` first** — it has the full frontmatter rules, the `.seoagent/` → OKF mapping table, and the quality bar. Then:
|
|
953
963
|
|
|
954
|
-
1. `seoagent okf scaffold`
|
|
955
|
-
2. Fill the bundle by mapping `.seoagent/` artifacts → OKF files (`index.md` from `context.md`/`project.md`; `concepts/*` from strategy clusters; `faqs/*`; `articles/*` from `content/` with `resource:` set to the live URL).
|
|
956
|
-
3. `seoagent okf validate` — fix every error (missing `type`, bad `timestamp`, broken link).
|
|
957
|
-
4.
|
|
964
|
+
1. `.seoagent/okf/` is already scaffolded — `seoagent init` does it, so there is nothing to create. (`seoagent okf scaffold` is still there for a project that predates that.)
|
|
965
|
+
2. Fill the bundle by mapping `.seoagent/` artifacts → OKF files (`index.md` from `context.md`/`project.md`; `concepts/*` from strategy clusters; `faqs/*`; `articles/*` from `content/` with `resource:` set to the live URL). **Replace every placeholder line the scaffold left behind** — while any of them survives, the bundle will not be published (placeholder text in front of an answer engine is worse than nothing).
|
|
966
|
+
3. `seoagent okf validate` — fix every error (missing `type`, bad `timestamp`, broken link). A bundle with errors is not published either.
|
|
967
|
+
4. **Publishing is automatic.** The next `seoagent sync` copies the filled, valid bundle into the project's static dir (`public/.well-known/okf/` or `static/.well-known/okf/`, per `public_dir:` in `project.md`) and regenerates + publishes `llms.txt` alongside it. Run `seoagent sync`, then **tell the user to commit and deploy the published files** — that last step is theirs, and it is the one that makes any of this visible. Use `seoagent okf publish` / `seoagent llms` if you want either half on demand.
|
|
968
|
+
- If sync reports it couldn't find a static dir, set `public_dir:` in `.seoagent/project.md` (`public` for Next.js/Vite/Astro, `static` for SvelteKit/Gatsby/Hugo) and re-run.
|
|
958
969
|
5. **Measure it.** The OKF bundle makes the business _citable_ — `seoagent citations` checks whether it's _working_. It runs buyer-intent queries through the Claude Agent SDK with live web search and writes `.seoagent/citations/scorecard.md` (which queries surface the business, and where it's missing). It's a real **tracker**, not a one-shot read: every run is saved to `.seoagent/citations/history/<ts>.json` and the scorecard shows the **trend** vs the last run, the **URL each engine cited** per query (theirs when the business loses — so you know what to beat), and a competitor **share-of-voice** table when you pass `seoagent citations --competitors "Frase,Otterly"` (or set a `competitors:` line in `context.md`). Run it after publishing, and again on a cadence to watch the trend. When the user asks "am I getting cited by AI?", "measure my AI visibility", "how do I compare to a competitor in AI answers?", or "is the OKF bundle working?", this is the command. It's a web-grounded proxy for ChatGPT/Perplexity/AI Overviews — directional, not a per-engine guarantee.
|
|
959
970
|
|
|
960
971
|
This is the AEO/GEO complement to schema markup: schema describes a single page in HTML; the OKF bundle describes the whole business for agents to load wholesale — and `seoagent citations` closes the loop by measuring whether answer engines actually cite it.
|
|
@@ -975,11 +986,12 @@ seoagent_version: 0.2.0
|
|
|
975
986
|
image_provider: openai # optional: openai | fal | replicate | none — auto-detected by `init`/`seoagent env-check` from OPENAI_API_KEY / FAL_KEY / REPLICATE_API_TOKEN
|
|
976
987
|
cms: strapi # optional: strapi | wordpress | sanity | contentful | ghost | webflow | shopify | payload | directus | mdx-local | none
|
|
977
988
|
blog_path: /blog # optional: detected from app/blog/, pages/blog/, etc.
|
|
989
|
+
public_dir: public # optional: the dir this project serves as static files — `public` (Next.js/Vite/Astro) or `static` (SvelteKit/Gatsby/Hugo). Auto-detected by `init`; it is where llms.txt and the OKF bundle get PUBLISHED, so a wrong value means none of that work is served.
|
|
978
990
|
---
|
|
979
991
|
# SEOAgent Project — example.com
|
|
980
992
|
```
|
|
981
993
|
|
|
982
|
-
`cms`, `blog_path`, and `
|
|
994
|
+
`cms`, `blog_path`, `image_provider`, and `public_dir` are detected by `seoagent init` from package.json deps, env files, and the filesystem. Update them manually if detection got it wrong. If a user adds an image-provider key after init, `seoagent env-check` re-detects and records it (see Phase 4 → Image Generation).
|
|
983
995
|
|
|
984
996
|
### `.seoagent/context.md`
|
|
985
997
|
|