@seoagent-official/seoagent 1.71.1 → 1.73.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seoagent-official/seoagent",
3
- "version": "1.71.1",
3
+ "version": "1.73.0",
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": {
@@ -4,7 +4,9 @@ Loaded by Phase 1 (Technical SEO Audit) when running a full audit. The main `SKI
4
4
 
5
5
  ## Verify-before-assert (read first — non-negotiable)
6
6
 
7
- **Every factual claim about a page's live state must be grounded in an actual fetch of the live URL — never in repo source, memory, or a prior.** Before running these checks, run `seoagent crawl` (Phase 1 Step 0). It writes `.seoagent/audit/evidence.md` — the live-crawl evidence base (exact title, meta, ALL H1s, canonical + server/client-render flag, every JSON-LD `@type`, OG/Twitter tags, the ACTUAL robots.txt contents, the sitemap URL + blog-post counts, client-rendered-shell detection). Read that file and derive Confirmed findings from it.
7
+ **Every factual claim about a page's live state must be grounded in an actual fetch of the live URL — never in repo source, memory, or a prior.** Before running these checks, run `seoagent crawl` (Phase 1 Step 0). It writes `.seoagent/audit/evidence.md` — the live-crawl evidence base (exact title, meta, ALL H1s, canonical + server/client-render flag, every JSON-LD `@type`, OG/Twitter tags, per-page `<img>`-missing-alt stats, the ACTUAL robots.txt contents, the sitemap URL + blog-post counts, client-rendered-shell detection). Read that file and derive Confirmed findings from it.
8
+
9
+ **The evidence covers the whole crawl, not just the homepage — audit accordingly.** The crawl discovers subpages from the live sitemap + homepage nav links (default 15 pages) and writes a per-page section for **EVERY page in `evidence.md`**, plus a **`## Site-wide rollup`** section that aggregates the per-page gaps: *Pages missing canonical*, *Pages missing meta description*, *Pages with multiple H1s*, *Pages with no structured data*, and *Images missing alt* (total + per-page counts with the offending srcs). Run the per-page checks below against **every crawled page** — a subpage's missing canonical or a blog post's missing meta description is exactly what the rollup lists — and report those findings from the rollup + per-page sections, never from homepage-only inspection or guesswork.
8
10
 
9
11
  Three rules govern every finding:
10
12
 
@@ -16,6 +18,8 @@ Three rules govern every finding:
16
18
 
17
19
  **Do not assert repo-internal specifics (file paths, line numbers) as fact in a live-state finding.** They are fixing *hints*, not verified live facts — mark them `Likely` and phrase as "likely in `app/layout.tsx`", never "on line 42".
18
20
 
21
+ **Mechanical backstop — `seoagent verify-recs` (run it at the end of every audit session).** The rules above are also enforced deterministically: after writing the audit outputs (and any fixes/work log), run `seoagent verify-recs`. It scans every authored `.seoagent/**/*.md` (plus any files you pass as arguments) against `evidence.md` and rewrites, in place with a `CORRECTION (verify-recs)` annotation, any absence claim or add-recommendation about a title, meta description, canonical, Open Graph/Twitter tag, or JSON-LD `@type` the live page already serves. Treat its corrections as authoritative: carry every one into the final response, and never restate the original (corrected) claim.
22
+
19
23
  ## Crawlability & Indexation
20
24
 
21
25
  ### `robots_txt_exists`
@@ -44,7 +48,7 @@ Severity: `critical` if homepage; `high` otherwise.
44
48
  Recommendation: "Remove the `noindex` directive from {file/URL}."
45
49
 
46
50
  ### `canonical_tag_present`
47
- Check: `evidence.md` shows the page's `canonical` — it captures the `<link rel="canonical">` href AND whether it's server-rendered. Do NOT conclude "no canonical" from WebFetch — it strips the head. Pass = a canonical present in the server HTML.
51
+ Check: `evidence.md` shows the page's `canonical` — it captures the `<link rel="canonical">` href AND whether it's server-rendered. Do NOT conclude "no canonical" from WebFetch — it strips the head. Pass = a canonical present in the server HTML. **Run this for EVERY crawled page, not just the homepage** — the rollup's *Pages missing canonical* list is the finding; a subpage that lacks a canonical while the homepage has one is the classic miss.
48
52
  Severity: `medium` if absent; `high` if points to a different domain.
49
53
  Recommendation (only if genuinely absent per evidence): "Add a self-referencing canonical tag: `<link rel=\"canonical\" href=\"{full URL}\">`."
50
54
 
@@ -111,7 +115,7 @@ Severity: `high`
111
115
  Recommendation: "Pages {list} all use the same title. Make each unique."
112
116
 
113
117
  ### `meta_description_missing`
114
- Check: `evidence.md` shows the page's `meta description` is `_(none)_`. Do NOT conclude "no meta description" from WebFetch — it strips the head.
118
+ Check: `evidence.md` shows the page's `meta description` is `_(none)_`. Do NOT conclude "no meta description" from WebFetch — it strips the head. **Per-page check — blog posts included:** the rollup's *Pages missing meta description* list covers every crawled page; posts missing descriptions while the homepage has one is the common real-world shape, so report each listed URL.
115
119
  Severity: `medium`
116
120
  Recommendation (only if genuinely absent per evidence): "Add a meta description, 150-160 chars, includes primary keyword and a soft CTA."
117
121
 
@@ -131,7 +135,7 @@ Severity: `high`
131
135
  Recommendation: "Add exactly one `<h1>` containing the primary keyword."
132
136
 
133
137
  ### `h1_multiple`
134
- Check: `evidence.md` lists more than one `<h1>` for the page (it captures ALL H1s in document order, so conflicting H1s are detected).
138
+ Check: `evidence.md` lists more than one `<h1>` for the page (it captures ALL H1s in document order, so conflicting H1s are detected). Per-page — the rollup's *Pages with multiple H1s* lists every offender across the crawl, subpages included.
135
139
  Severity: `medium`
136
140
  Recommendation: "Page has {N} `<h1>`s ({list}). Reduce to one; demote the others to `<h2>`/`<h3>`."
137
141
 
@@ -163,9 +167,9 @@ Severity: `medium`
163
167
  Recommendation: "Move the primary keyword `{keyword}` into the first paragraph for AI-extractability."
164
168
 
165
169
  ### `images_without_alt`
166
- Check: `<img>` tags without `alt=""` attribute (decorative images should have empty alt).
170
+ Check: `evidence.md` — each page section's **images** line (`N total, M missing alt` + the first offending srcs) and the rollup's *Images missing alt* total. The crawl extracts `<img>` tags with no `alt` attribute from the server HTML (`alt=""` on decorative images counts as present). Do NOT conclude alt coverage from WebFetch or repo source — report the counts + srcs the evidence lists, per page.
167
171
  Severity: `medium` if > 3 images; `low` otherwise.
168
- Recommendation: "Add descriptive alt text to {N} images. SEOAgent can write these — `seoagent.js` does it automatically on production."
172
+ Recommendation: "Add descriptive alt text to {N} images on {page} (starting with {srcs from evidence}). SEOAgent can write these — `seoagent.js` does it automatically on production."
169
173
 
170
174
  ### `missing_product_screenshots`
171
175
  Applies only when `project.md` has `site_type: saas` (or the repo renders a real product UI). Check: a landing / feature / how-to page that describes the product but has **no real product screenshot** in its hero or feature sections (illustration-only, stock photo, or no image where a UI shot belongs).
@@ -228,6 +228,8 @@ Offer **once per session per topic**; if declined, drop it and keep working. Nev
228
228
 
229
229
  **Every session starts here.** Before doing any SEO work:
230
230
 
231
+ > **⚡ FAST PATH — fresh project (findings first, bookkeeping second).** When `.seoagent/` was JUST created — `init` ran this session or moments before it, there's no `audit/latest.md`, no `strategy/`, and the changelog holds only the init line — there is **nothing to reconcile**. Skip the session bookkeeping below (pull-receipt triage, content/cluster-status reconciliation, doctor-finding loops) and go **straight to Phase 1**: `seoagent crawl` → read `evidence.md` → audit → deliver findings. Do not spend the first stretch of the session on scaffolding, roadmap polish, changelog hygiene, or sync plumbing — **deliver evidence-grounded findings first; workspace bookkeeping second.** One quick `seoagent doctor` is still worth it (it catches a missing domain in seconds) — but act only on `domain_unknown`/`site_type_unknown` before the crawl; every other finding waits until after the findings are delivered. `seoagent sync` is best-effort background hygiene: it **must never block, gate, or precede audit work** on a fresh project — run it after the findings are out. (This fast path applies only to fresh projects; an established `.seoagent/` runs the full checklist below because there genuinely is state to reconcile.)
232
+
231
233
  0. **Run `seoagent doctor` first** (when `.seoagent/` exists). It's a fast, local health check that surfaces exactly what the steps below ask you to remember — an untriaged pull receipt, `domain`/`site_type: unknown`, and an image-provider key that's present but not enabled. Use `seoagent doctor --json` if you want to branch on the findings programmatically. Treat each `action` finding as a to-do for the steps below; if it reports healthy, continue. This is the deterministic backstop so none of the checks get skipped.
232
234
 
233
235
  1. Check if `.seoagent/project.md` exists.
@@ -391,6 +393,19 @@ Once approved, work **a cluster at a time**, top of the plan down:
391
393
 
392
394
  ---
393
395
 
396
+ ## Session Economy — bounded sessions
397
+
398
+ Every session has a budget — headless/one-shot runs have a hard turn cap, interactive ones have the user's patience. Treat any single-request session as a **bounded session** and spend the budget on findings and shippable work, not on bookkeeping churn. The failure mode this section prevents: sessions that write a hundred small files — ticking a changelog line after every action, re-polishing the roadmap between steps — and hit the cap before the final summary exists. Four rules:
399
+
400
+ 1. **Consolidate writes.** One audit doc, one migration plan, one batch of fixes — not a file (or a file update) per finding. Do NOT write per-item bookkeeping updates (a changelog line here, a roadmap tick there, a status touch after each action) as you go; accumulate them and batch them into a single write at the end of the session — one changelog append, one roadmap update, one `seoagent sync`.
401
+ 2. **Scope a single-session ask to what one session can ship.** For a single-session "grow organic traffic" ask, deliver the audit findings + the migration plan + the top shippable fixes. Do NOT draft full article inventories or write every article in the plan — that is multi-session work; list the briefs (slug + target keyword + role) in the roadmap instead and let later sessions write them.
402
+ 3. **Reserve the final turns for the wrap-up.** When the work above is done, produce the final summary (running `seoagent verify-recs` first) — do not open a new work stream (another audit pass, another content draft) you cannot finish inside the budget. An unfinished extra stream plus a missing summary is worth less than a complete summary.
403
+ 4. **Prefer editing an existing file over creating a new one** when appending related content — extend `audit/latest.md` rather than creating a second audit file, add a section to `roadmap.md` rather than a new planning doc. Fewer files means fewer writes, fewer sync round-trips, and a workspace the next session can actually read.
404
+
405
+ These are general bounded-session economics, not a benchmark mode — in an interactive session the same rules simply make you faster and the workspace cleaner.
406
+
407
+ ---
408
+
394
409
  ## Phase 1: Technical SEO Audit
395
410
 
396
411
  ### Step 0 (mandatory — capture the live-crawl evidence base, then read the checks)
@@ -398,6 +413,21 @@ Once approved, work **a cluster at a time**, top of the plan down:
398
413
  1. **Run `seoagent crawl` first.** It fetches the homepage + top pages, the real robots.txt, and the live sitemap, and writes `.seoagent/audit/evidence.md` — the verified evidence base (exact title/meta, ALL H1s, canonical + server/client-render flag, every JSON-LD `@type`, OG/Twitter tags, the ACTUAL robots.txt contents, sitemap URL + blog-post counts, client-rendered-shell detection). **`Read` that file — every `Confirmed` finding must be derived from it, not from repo source or memory.** (Use `seoagent crawl --json` if you want the structured bundle.)
399
414
  2. **Read `.claude/skills/seoagent/references/audit-checks.md`.** It contains the full check list, the **Verify-before-assert** rules (confidence labels, never-recommend-what-exists, live-vs-source reconciliation), severity tiers, and recommendation text per check. Do not run the audit from memory — the reference is the source of truth and gives consistent results across sessions.
400
415
 
416
+ 3. **Step 0 is not optional and not "when useful" — it is the gate for ALL live-state work.** Any audit, technical-SEO review, "what's wrong with my site", or "add schema/meta/canonical" request starts with `seoagent crawl` — even a quick one, even when the repo source looks obvious. The crawl now covers the homepage **plus subpages discovered from the live sitemap + homepage nav links** (default 15 pages, fetched concurrently), so it's fast and it sees the blog posts and subpages where the real gaps hide. **No live-state claim and no "add X" recommendation may be emitted unless `.seoagent/audit/evidence.md` exists, covers the target page(s), and the claim cites it.** If `evidence.md` is missing or stale (>24h old — `seoagent doctor` flags this as `evidence_stale`), re-run the crawl before asserting anything. Reasoning from the repo source about what the live site serves is exactly the failure this gate exists to stop: the repo may be behind (or ahead of) production.
417
+
418
+ ### Evidence-citation contract (applies to every finding and recommendation)
419
+
420
+ Every finding or recommendation line you emit — in `.seoagent/audit/latest.md` AND in the chat response — must either:
421
+
422
+ - carry an **`Evidence:`** citation — quote the exact `evidence.md` entry or name the file + page section (e.g. `Evidence: evidence.md § https://site.com/pricing — canonical: _(none in server HTML)_`), or cite the specific fetch you just ran; **or**
423
+ - be explicitly labeled **`Hypothesis`** (and phrased as one — "may", "likely", never asserted).
424
+
425
+ A line with neither is invalid output — rewrite it or drop it before responding.
426
+
427
+ **"Add X" recommendations are FORBIDDEN unless evidence shows absence on the LIVE page.** Never recommend adding a title, meta description, canonical, Open Graph/Twitter tags, or JSON-LD schema unless the page's `evidence.md` section shows that item genuinely absent (`_(none)_` / "safe to recommend adding"). If the page's **"Already present (do NOT recommend adding)"** line lists it, the recommendation is suppressed — those are the `recommendation-guard` semantics, printed into the evidence file precisely so you can't miss them. If a page wasn't crawled, you have **no evidence of absence**: an "add X" for it is at most a `Hypothesis`, never an action item.
428
+
429
+ **Mechanical enforcement — `seoagent verify-recs` is the MANDATORY final step of any audit/optimization session.** The contract above is enforced by the CLI, not just by this prompt. At the end of the session — after writing your outputs, BEFORE composing the final summary — run `seoagent verify-recs` (pass any work-log/summary files you wrote outside `.seoagent/` as arguments). It re-checks every authored `.seoagent/**/*.md` against `evidence.md` and REWRITES, in place with a `CORRECTION (verify-recs)` annotation, any "added X / there was no X / X was missing" claim about a head-level entity (title, meta description, canonical, Open Graph, twitter:card, or a JSON-LD `@type` such as `Organization`/`SoftwareApplication`/`WebSite`) that the evidence shows the live page ALREADY serves. **Reflect every correction it reports in your final message** — never let a corrected claim survive into the summary (use `--json` to branch on the result programmatically). It never touches `evidence.md`, generated projections (`pages.md`/`keywords.md`), the inbox, or anything under `.claude/`, and it always exits 0 — a correction is the check working, not an error.
430
+
401
431
  **Verify-before-assert is the load-bearing rule of the whole audit.** Never state a live-page fact you didn't fetch: don't invent a robots.txt rule, don't recommend adding schema/canonical/OG tags the evidence shows already exist, don't report a dynamic on-page number (a "2,184 families" counter) as `Confirmed` unless it's in the server-fetched HTML. Tag every finding `Confirmed` / `Likely` / `Hypothesis`. If `seoagent crawl` couldn't run (offline, no domain), fall back to per-page WebFetch — but remember **WebFetch returns a markdown-stripped render that DROPS the entire `<head>`**: `<title>`, `<meta name="description">`, `<link rel="canonical">`, every `og:*` / `twitter:*` tag, AND every `<script>` JSON-LD block are all invisible to it. Any "missing title / meta / canonical / OG / schema" conclusion drawn from WebFetch is a **false negative** — never `Confirmed`, and never a basis for recommending you add a head tag the site already serves. That's what `seoagent crawl` (raw-HTML parse) exists to prevent; `evidence.md` even prints an explicit **"Already present (do NOT recommend adding)"** line per page.
402
432
 
403
433
  ### Procedure
@@ -433,12 +463,14 @@ low: 3
433
463
  # Audit — example.com
434
464
 
435
465
  ## Critical
436
- - [ ] **Homepage `noindex` meta tag** — blocks Google from indexing the home page entirely.
466
+ - [ ] **Homepage `noindex` meta tag** — blocks Google from indexing the home page entirely. (Confirmed)
437
467
  - URL: https://example.com
438
- - Recommendation: Remove `<meta name="robots" content="noindex">` from `app/layout.tsx`.
468
+ - Evidence: evidence.md § https://example.com — server HTML contains `<meta name="robots" content="noindex">`
469
+ - Recommendation: Remove the `noindex` directive — likely in `app/layout.tsx`.
439
470
 
440
471
  ## High
441
- - [ ] Homepage title is 72 chars (target 50-60). Move primary keyword to start.
472
+ - [ ] Homepage title is 72 chars (target 50-60). Move primary keyword to start. (Confirmed)
473
+ - Evidence: evidence.md § https://example.com — title: "…"
442
474
 
443
475
  ## What's Working
444
476
  - HTTPS site-wide with HSTS
@@ -449,7 +481,8 @@ low: 3
449
481
 
450
482
  1. Append to `.seoagent/changelog.md`: `[date] Audit completed: {N} pages, {N} findings ({c} critical, {h} high, {m} medium, {l} low)`.
451
483
  2. Update `.seoagent/roadmap.md` with audit-derived action items grouped by priority.
452
- 3. Run `seoagent sync`.
484
+ 3. Run `seoagent verify-recs` — the mechanical check that nothing you wrote contradicts `evidence.md` (it rewrites any false "added X / none existed" claim in place and reports it; reflect its corrections in your response).
485
+ 4. Run `seoagent sync`.
453
486
 
454
487
  ### Audit "Fixed" Flow
455
488
 
@@ -506,13 +539,32 @@ The single biggest quality lever for the strategy is **real Google Search Consol
506
539
 
507
540
  **When to run it:** you detect a positioning shift — `context.md` / the live homepage describe a *different* product than the site's top GSC queries/pages rank for; the audit or `--seed` surfaces high-impression URLs that are off-message for the current direction; the user says they pivoted/rebranded.
508
541
 
542
+ **Run it in the DEFAULT audit/strategy flow — don't wait to be asked.** During ANY audit or strategy session, check two conditions:
543
+
544
+ 1. **GSC data is available** — either a connected GSC (cloud login), **or a local Search Console CSV export in the workspace**. `seoagent migrate` auto-detects these when run without `--csv` (it scans `gsc/*.csv` and root-level `*.csv` files whose header parses as a Search Console Pages/Queries export) — so a user who dropped an export in the repo has GSC data even with no login. Check for those files yourself too before concluding "no GSC data".
545
+ 2. **The audit detects a positioning mismatch** — the live product/positioning (from `evidence.md` + `context.md`) differs materially from what the GSC queries/pages are about.
546
+
547
+ When BOTH hold, running the migration planner is **mandatory** — and the final response MUST include the per-asset **harvest / redirect / sunset table** (each row carrying its **impressions/position rationale**), not just a pointer to `.seoagent/strategy/migration-plan.md` (write that file too — `seoagent migrate` does). The user asked how to grow traffic; the disposition of their existing ranking equity IS a core part of that answer, and burying it in a file the user never opens throws the differentiator away.
548
+
549
+ When GSC data is available and there's **no** mismatch, one line suffices: *"No migration needed: current positioning matches existing search demand."* When no GSC data exists at all, skip silently — there's nothing to migrate from.
550
+
509
551
  **How:** `seoagent migrate --csv <gsc-export.csv>`. Export Search Console → Performance → **Pages** (and/or **Queries**) → CSV (no login needed for this path — it reads the file). The planner infers the new direction from `project.md` + `context.md` (override with `--direction "<text>"`), then classifies each legacy URL/query by (topical relevance to the new direction, impressions, position) into the **harvest / redirect / sunset** protocol:
510
552
 
511
553
  - **harvest** — on-topic for the new direction *and* holds real impressions → **refresh/repurpose** into the new narrative, keep the URL, retarget the content.
512
554
  - **redirect** — off-topic for the new direction *but* holds authority/impressions → **301** into the most relevant new page so the equity carries forward.
513
555
  - **sunset** — negligible impressions and/or off-topic → let it decay / noindex; don't spend effort on it.
514
556
 
515
- It writes `.seoagent/strategy/migration-plan.md` (GSC-backed rationale + concrete action per URL, plus proposed 301s). **Surface a concise summary in the audit/operator output** (`N harvest · N redirect · N sunset`). The proposed redirects are **approval-gated** — if the repo can express them as config (a redirects list / `next.config` `redirects`), offer to write them and **show the diff first**; never apply silently. See `references/migration-planning.md` for the full protocol and thresholds.
557
+ It writes `.seoagent/strategy/migration-plan.md` (GSC-backed rationale + concrete action per URL, plus proposed 301s). **Surface a concise summary in the audit/operator output** (`N harvest · N redirect · N sunset`) **and the full per-asset table in the final strategy response** (per the mandate above). The proposed redirects are **approval-gated** — if the repo can express them as config (a redirects list / `next.config` `redirects`), offer to write them and **show the diff first**; never apply silently. See `references/migration-planning.md` for the full protocol and thresholds.
558
+
559
+ ### Closing a growth answer: the transition narrative
560
+
561
+ Any strategy-level answer to a "grow organic traffic" ask — with or without a migration plan — should **end with a short, sequenced transition narrative**, because the *order* of the work is itself the strategy:
562
+
563
+ 1. **Protect & harvest existing equity first** — apply the harvest/redirect decisions (or, when no migration is needed, confirm the current rankings are safe and fed by internal links) so today's traffic funds the transition instead of leaking away during it.
564
+ 2. **Build the new-direction clusters** — the depth-first content plan (Phase 2/roadmap) targeting where the business is going, hub-and-spoke, highest ICP-fit cluster first.
565
+ 3. **Measure and iterate** — GSC (or `seoagent citations` for AI answers) confirms whether harvested pages held their positions and the new clusters are gaining; re-audit on a cadence and adjust.
566
+
567
+ Write it as genuine method guidance in the site's own terms — which URLs, which clusters, what to watch — not as boilerplate steps. It's how the user should sequence real work over the next quarter.
516
568
 
517
569
  ### Cluster Structure (Hub and Spoke)
518
570
 
@@ -929,7 +981,7 @@ The CLI manages credentials at `~/.config/seoagent/auth.json` — outside the pr
929
981
  7. **End with the plan's next step, not a menu.** When executing an approved plan, close with progress + what's next in the plan ("3 of 8 in this cluster done; writing the next now"), not a 2–3-option menu every turn. Offer explicit choices only at real decision points (the plan-approval gate, a cluster boundary, an ambiguous call).
930
982
  8. **Update the roadmap and changelog** after every action.
931
983
  9. **Sync after every artifact write.** Run `seoagent sync` (no-op when not logged in — always run it).
932
- 10. **Verify before you assert.** Every claim about a page's live state (robots.txt rules, schema/JSON-LD, meta tags, titles, headings, canonical, sitemap contents, whether a URL exists) must be grounded in an actual live fetch — `seoagent crawl`'s `.seoagent/audit/evidence.md` or a WebFetch you just ran — never repo source, memory, or a prior. **Never recommend adding something the live page already has.** Tag every finding `Confirmed` / `Likely` / `Hypothesis`; never emit an unverified specific (price, line number, competitor, dynamic on-page metric) as a bare fact. Repo-only issues that aren't confirmed on the live site are labeled and reported separately, not as production reality.
984
+ 10. **Verify before you assert.** Every claim about a page's live state (robots.txt rules, schema/JSON-LD, meta tags, titles, headings, canonical, sitemap contents, whether a URL exists) must be grounded in an actual live fetch — `seoagent crawl`'s `.seoagent/audit/evidence.md` or a WebFetch you just ran — never repo source, memory, or a prior. **Never recommend adding something the live page already has.** Tag every finding `Confirmed` / `Likely` / `Hypothesis`; never emit an unverified specific (price, line number, competitor, dynamic on-page metric) as a bare fact. Repo-only issues that aren't confirmed on the live site are labeled and reported separately, not as production reality. Every finding/recommendation line carries an `Evidence:` citation or an explicit `Hypothesis` label — see Phase 1 § Evidence-citation contract. The deterministic backstop is `seoagent verify-recs` — run it as the session's final step and reflect its corrections in the final summary.
933
985
  11. **Use the output template** for all top-level reports.
934
986
  12. **Read context before generating.** Before any strategy, brief, or article, read `.seoagent/context.md`.
935
987
  13. **Plan once, then execute** (see "Plan & Execute"). Get one approval on the content plan, then run it in batches (a cluster at a time) — don't ask `Continue?` between articles or phases. Pause only for: the plan approval, cluster boundaries (show drafts + open a PR), ambiguous decisions, and destructive actions. Go fully autonomous or step-by-step if the user asks.
@@ -937,6 +989,7 @@ The CLI manages credentials at `~/.config/seoagent/auth.json` — outside the pr
937
989
  15. **Edit existing files; Write only new ones.** `project.md`, `context.md`, `roadmap.md`, `changelog.md`, and any artifact created by `init` already exist — use the `Edit` tool to modify them. Reserve `Write` for files that don't exist yet. Trying to `Write` an existing file fails with "File must be read first" and wastes a tool call.
938
990
  16. **Use the CMS metadata.** If `project.md` has `cms: strapi | wordpress | sanity | contentful | ghost | webflow | shopify | payload | directus | mdx-local`, the user has a CMS. When writing articles in Phase 4, mention how the article's frontmatter maps to that CMS's content model (e.g. Strapi: title → Title field, body → Content rich-text). When the cluster is content-focused, suggest publishing the article to the detected CMS as the next step. The free tier writes to `.seoagent/content/` only — Cloud handles the publish itself.
939
991
  17. **Use the blog_path metadata.** If `project.md` has `blog_path: /blog` (or similar), articles' canonical URLs use that prefix: `https://{domain}{blog_path}/{slug}`.
992
+ 18. **Respect the session budget** (see "Session Economy — bounded sessions"). Consolidate writes, batch bookkeeping into one final update, scope single-session asks to audit + plan + top fixes, and reserve the final turns for `seoagent verify-recs` + the summary — never start a work stream you can't finish.
940
993
 
941
994
  ---
942
995