@hanzlaa/rcode 4.3.2 → 4.4.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/AGENTS.md +1 -1
- package/CONTRIBUTING.md +2 -1
- package/README.md +45 -10
- package/cli/doctor.js +21 -3
- package/cli/index.js +5 -1
- package/cli/install.js +16 -2
- package/cli/postinstall.js +1 -1
- package/cli/uninstall.js +48 -6
- package/dist/rcode.js +178 -174
- package/package.json +12 -22
- package/rcode/agents/rcode-codebase-mapper.md +12 -0
- package/rcode/agents/rcode-phase-researcher.md +13 -0
- package/rcode/agents/rcode-project-researcher.md +32 -0
- package/rcode/agents/rcode-roadmapper.md +15 -0
- package/rcode/agents/rules/planner/common-patterns.md +40 -0
- package/rcode/bin/lib/roadmap.cjs +184 -11
- package/rcode/bin/rcode-hooks.cjs +303 -14
- package/rcode/bin/rcode-tools.cjs +669 -55
- package/rcode/commands/lens-audit.md +8 -6
- package/rcode/data/intent-table.json +87 -0
- package/rcode/modules/seo.yaml +22 -0
- package/rcode/references/project-types.yaml +75 -0
- package/rcode/skills/SKILLS_INDEX.md +20 -2
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/SKILL.md +16 -21
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/rules/backlog-building.md +13 -0
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/rules/merge-strategy.md +17 -0
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/rules/orchestrator-rhythm.md +9 -0
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/rules/wave-design.md +21 -0
- package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/templates/heartbeat.sh +0 -0
- package/rcode/skills/actions/4-implementation/rcode-scaffold-project/SKILL.md +60 -1
- package/rcode/skills/core/rcode-lazy/SKILL.md +149 -0
- package/rcode/skills/seo/module.yaml +20 -0
- package/rcode/skills/seo/on-page-seo-auditor/SKILL.md +308 -0
- package/rcode/skills/seo/on-page-seo-auditor/references/audit-example.md +109 -0
- package/rcode/skills/seo/on-page-seo-auditor/references/audit-templates.md +427 -0
- package/rcode/skills/seo/on-page-seo-auditor/references/bulk-audit-playbook.md +116 -0
- package/rcode/skills/seo/on-page-seo-auditor/references/scoring-rubric.md +525 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/SKILL.md +94 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/rules/city-matrix-and-pages.md +76 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/rules/monetization.md +70 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/rules/niche-selection.md +60 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/rules/subniche-discovery.md +66 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/templates/service-city-page.md +36 -0
- package/rcode/skills/seo/rank-and-rent-local-seo/templates/subniche-research-prompt.md +34 -0
- package/rcode/skills/seo/seo-audit/SKILL.md +412 -0
- package/rcode/skills/seo/seo-audit/evals/evals.json +136 -0
- package/rcode/skills/seo/seo-audit/references/ai-writing-detection.md +200 -0
- package/rcode/skills/seo/seo-content-factory/SKILL.md +130 -0
- package/rcode/skills/seo/seo-content-factory/rules/agents.md +80 -0
- package/rcode/skills/seo/seo-content-factory/rules/herdr-wave-mapping.md +80 -0
- package/rcode/skills/seo/seo-content-factory/rules/pipeline.md +102 -0
- package/rcode/skills/seo/seo-content-factory/rules/programmatic-pages.md +107 -0
- package/rcode/skills/seo/seo-content-factory/rules/quality-gates.md +68 -0
- package/rcode/skills/seo/seo-content-factory/rules/weekly-cadence.md +61 -0
- package/rcode/skills/seo/seo-content-factory/templates/BACKLOG.md +23 -0
- package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/01-funnel-A1-A4.md +63 -0
- package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/02-fanout-editorial-A5-A6-A8.md +28 -0
- package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/03-fanout-programmatic-A7-A6-A8.md +25 -0
- package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/04-loop-A9-A10.md +34 -0
- package/rcode/skills/seo/seo-content-factory/templates/article.mdx +39 -0
- package/rcode/skills/seo/seo-content-factory/templates/cluster.schema.json +52 -0
- package/rcode/skills/seo/seo-content-factory/templates/content-brief.md +51 -0
- package/rcode/skills/seo/seo-content-factory/templates/jsonld-builders.ts +49 -0
- package/rcode/skills/seo/seo-content-factory/templates/keywords.csv +13 -0
- package/rcode/skills/seo/seo-content-factory/templates/programmatic-page.tsx +58 -0
- package/rcode/skills/seo/seo-content-writer/SKILL.md +263 -0
- package/rcode/skills/seo/seo-content-writer/references/content-structure-templates.md +875 -0
- package/rcode/skills/seo/seo-content-writer/references/instructions-detail.md +239 -0
- package/rcode/skills/seo/seo-content-writer/references/seo-writing-checklist.md +250 -0
- package/rcode/skills/seo/seo-content-writer/references/title-formulas.md +339 -0
- package/rcode/skills/seo/seo-growth-orchestrator/SKILL.md +79 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/backlinks.md +29 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/content-engine.md +27 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/dos-and-donts.md +40 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/goals-protocol.md +34 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/local-seo-stack.md +35 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/mrr-sprint.md +27 -0
- package/rcode/skills/seo/seo-growth-orchestrator/rules/tools.md +19 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/backlink-research.md +29 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/goal-protocol.md +35 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/local-citations.md +24 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/local-city-pages.md +27 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/local-gbp-categories.md +23 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/local-gsc-goldmine.md +27 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/local-review-mining.md +26 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-30day-plan.md +19 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-cut.md +13 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-opportunity-finder.md +17 -0
- package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-role-model.md +18 -0
- package/rcode/skills/seo/seo-site-builder/SKILL.md +149 -0
- package/rcode/skills/seo/seo-site-builder/rules/01-niche-discovery.md +64 -0
- package/rcode/skills/seo/seo-site-builder/rules/02-deep-research.md +164 -0
- package/rcode/skills/seo/seo-site-builder/rules/03-keyword-strategy.md +82 -0
- package/rcode/skills/seo/seo-site-builder/rules/04-content-plan.md +173 -0
- package/rcode/skills/seo/seo-site-builder/rules/05-site-build.md +187 -0
- package/rcode/skills/seo/seo-site-builder/rules/06-yolo.md +127 -0
- package/rcode/skills/seo/seo-site-builder/templates/article-stub.mdx +62 -0
- package/rcode/skills/seo/seo-site-builder/templates/image-prompt.md +97 -0
- package/rcode/skills/seo/seo-site-builder/templates/keyword-export.md +45 -0
- package/rcode/skills/seo/seo-site-builder/templates/niche-scorecard.md +28 -0
- package/rcode/skills/seo/technical-seo-checker/SKILL.md +329 -0
- package/rcode/skills/seo/technical-seo-checker/references/bulk-audit-playbook.md +118 -0
- package/rcode/skills/seo/technical-seo-checker/references/ecommerce-platform-patterns.md +166 -0
- package/rcode/skills/seo/technical-seo-checker/references/http-status-codes.md +705 -0
- package/rcode/skills/seo/technical-seo-checker/references/llm-crawler-handling.md +257 -0
- package/rcode/skills/seo/technical-seo-checker/references/pre-migration-playbook.md +137 -0
- package/rcode/skills/seo/technical-seo-checker/references/robots-txt-reference.md +717 -0
- package/rcode/skills/seo/technical-seo-checker/references/technical-audit-example.md +169 -0
- package/rcode/skills/seo/technical-seo-checker/references/technical-audit-templates.md +436 -0
- package/rcode/templates/settings-hooks.json +16 -1
- package/rcode/workflows/do.md +17 -0
- package/rcode/workflows/enable-hooks.md +3 -2
- package/rcode/workflows/execute-sprint.md +22 -0
- package/rcode/workflows/execute.md +17 -3
- package/rcode/workflows/lens-audit.md +49 -8
- package/rcode/workflows/new-milestone.md +21 -9
- package/rcode/workflows/new-project-create-roadmap.md +2 -0
- package/rcode/workflows/new-project-roadmap.md +2 -0
- package/rcode/workflows/new-project.md +3 -0
- package/rcode/workflows/plan.md +15 -2
- package/server/dashboard.js +6 -2
- package/server/lib/api.js +35 -20
- package/server/lib/html/client/components/OrchPanel.js +43 -2
- package/server/lib/html/client/components/dashboard/InProgress.js +5 -4
- package/server/lib/html/client/components/shared.js +14 -0
- package/server/lib/html/client/orchestrator.js +13 -0
- package/server/lib/html/client/views/KanbanView.js +33 -4
- package/server/lib/html/css.js +57 -3
- package/server/lib/scanner.js +40 -4
- package/server/orchestrator.js +42 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Programmatic Pages — marketing/ wiring
|
|
2
|
+
|
|
3
|
+
This is the concrete Next.js 16 App Router implementation for the canonical `marketing/`
|
|
4
|
+
site (`/home/hanzla/development/teaching/schedule-manager/marketing`). It honors the site's
|
|
5
|
+
existing conventions: **TS data files in `src/data/` (programmatic) + MDX (editorial)**.
|
|
6
|
+
Do NOT add a CMS, contentlayer, gray-matter-DB, or runtime fetching — the site is SSG.
|
|
7
|
+
|
|
8
|
+
## Two output channels
|
|
9
|
+
|
|
10
|
+
| Channel | Source | Route | Scale | Use for |
|
|
11
|
+
|---------|--------|-------|-------|---------|
|
|
12
|
+
| **Programmatic** | `src/data/seo/*.ts` (typed) | `src/app/(seo)/[...]/page.tsx` + `generateStaticParams` | 1,000s | service×city, service×industry, location pages |
|
|
13
|
+
| **Editorial (MDX)** | `src/content/<type>/*.mdx` | `src/app/blog/[slug]` (already a shell) + new `alternatives`/`comparisons` | ~100 | alternatives, comparisons, cornerstone, statistics, questions |
|
|
14
|
+
|
|
15
|
+
## Programmatic: the 2,000-page pattern
|
|
16
|
+
|
|
17
|
+
100 cities × 20 services = 2,000 pages from **~5 files**, not 2,000 files.
|
|
18
|
+
|
|
19
|
+
### 1. Dimension registries — `src/data/seo/` (matches existing `src/data/*.ts`)
|
|
20
|
+
```ts
|
|
21
|
+
// src/data/seo/services.ts
|
|
22
|
+
export interface SeoService {
|
|
23
|
+
slug: string; name: string; h1: string;
|
|
24
|
+
benefits: string[]; painPoints: string[]; faqs: { q: string; a: string }[];
|
|
25
|
+
}
|
|
26
|
+
export const services: SeoService[] = [ /* 20 records, A7-generated */ ]
|
|
27
|
+
|
|
28
|
+
// src/data/seo/cities.ts
|
|
29
|
+
export interface SeoCity { slug: string; name: string; region: string; country: string }
|
|
30
|
+
export const cities: SeoCity[] = [ /* 100 records */ ]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. One dynamic route for the cross-product
|
|
34
|
+
```tsx
|
|
35
|
+
// src/app/(seo)/[service]/[city]/page.tsx
|
|
36
|
+
import { services } from '@/data/seo/services'
|
|
37
|
+
import { cities } from '@/data/seo/cities'
|
|
38
|
+
import { notFound } from 'next/navigation'
|
|
39
|
+
|
|
40
|
+
export function generateStaticParams() {
|
|
41
|
+
return services.flatMap(s => cities.map(c => ({ service: s.slug, city: c.slug })))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function generateMetadata({ params }) {
|
|
45
|
+
const { service, city } = await params
|
|
46
|
+
const s = services.find(x => x.slug === service); const c = cities.find(x => x.slug === city)
|
|
47
|
+
if (!s || !c) return {}
|
|
48
|
+
return {
|
|
49
|
+
title: `${s.name} in ${c.name} | LeadLyze`,
|
|
50
|
+
description: `${s.name} for ${c.name} businesses — ${s.benefits[0]}. Book more meetings with LeadLyze.`,
|
|
51
|
+
alternates: { canonical: `https://leadlyze.com/${service}/${city}` },
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default async function Page({ params }) {
|
|
56
|
+
const { service, city } = await params
|
|
57
|
+
const s = services.find(x => x.slug === service); const c = cities.find(x => x.slug === city)
|
|
58
|
+
if (!s || !c) notFound()
|
|
59
|
+
// Hero → Benefits → Case Studies → Pricing → FAQ → CTA, all composed from s + c
|
|
60
|
+
// ...
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
Full route template: `templates/programmatic-page.tsx`.
|
|
64
|
+
|
|
65
|
+
### 3. Thin-content guard (mandatory — see quality-gates.md)
|
|
66
|
+
Templated pages are the #1 thin-content / doorway-page risk. Each page MUST inject ≥2
|
|
67
|
+
**city-specific or service-specific** unique elements (local stat, named local use-case,
|
|
68
|
+
varied intro sentence keyed off `c.region`/`s.painPoints`) so no two pages are near-duplicates.
|
|
69
|
+
A page that's pure boilerplate with the city name swapped ships as `noindex`.
|
|
70
|
+
|
|
71
|
+
## Editorial: the MDX channel
|
|
72
|
+
|
|
73
|
+
The blog `[slug]` shell already says *"fetch MDX/CMS content by slug"*. Wire it minimally:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// src/lib/mdx.ts — tiny loader, no DB
|
|
77
|
+
import { compileMDX } from 'next-mdx-remote/rsc' // add dep ONLY with user consent
|
|
78
|
+
import fs from 'node:fs/promises'
|
|
79
|
+
export async function getDoc(type: string, slug: string) { /* read src/content/<type>/<slug>.mdx, compile */ }
|
|
80
|
+
export async function listSlugs(type: string) { /* readdir, strip .mdx */ }
|
|
81
|
+
```
|
|
82
|
+
> **DECIDED (2026-06-14):** use `next-mdx-remote` for the editorial channel. It's a new dep —
|
|
83
|
+
> add it at Phase 0 (`pnpm add next-mdx-remote`) and confirm `pnpm build` still passes before
|
|
84
|
+
> wave 1. (Zero-dep fallback, only if the user reverses: structured TS bodies rendered via the
|
|
85
|
+
> existing `src/components/blog` components.)
|
|
86
|
+
|
|
87
|
+
`generateStaticParams` for blog/alternatives/comparisons then returns `listSlugs(type)`.
|
|
88
|
+
|
|
89
|
+
## Schema (A8) — extend the existing helper
|
|
90
|
+
|
|
91
|
+
`src/lib/jsonld.ts` already exists. Add typed builders (`faqPage`, `softwareApplication`,
|
|
92
|
+
`product`, `breadcrumbList`, `aggregateRating`) and render via a `<JsonLd>` component —
|
|
93
|
+
never hand-write `<script type="application/ld+json">` strings inline.
|
|
94
|
+
|
|
95
|
+
## Sitemap
|
|
96
|
+
|
|
97
|
+
`next-sitemap` is already configured (`next-sitemap.config.js`, siteUrl leadlyze.com). It
|
|
98
|
+
crawls the built `.next` output, so all `generateStaticParams` pages are included
|
|
99
|
+
automatically on `pnpm build && next-sitemap`. For 2,000+ URLs, enable sitemap splitting:
|
|
100
|
+
add `sitemapSize: 5000` (default already chunks at 5k) — verify `robots.txt` references the
|
|
101
|
+
index. No per-page sitemap code needed.
|
|
102
|
+
|
|
103
|
+
## Establishing the content layer (Phase 0, once)
|
|
104
|
+
|
|
105
|
+
If `src/data/seo/` and `src/app/(seo)/` don't exist yet, the orchestrator scaffolds them
|
|
106
|
+
before wave 1: create the dirs, drop the route template + empty typed registries, confirm
|
|
107
|
+
`pnpm build` still passes (baseline). Only THEN do fan-out waves populate them.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Quality Gates — the firewall against AI slop & thin pages
|
|
2
|
+
|
|
3
|
+
Scaling to 2,000 pages is worthless if Google classifies them as thin/doorway/spam. These
|
|
4
|
+
gates are non-negotiable. A page that fails ships as `noindex`, never as raw indexable content.
|
|
5
|
+
|
|
6
|
+
## Gate 1 — Briefs before prose (hard)
|
|
7
|
+
|
|
8
|
+
The Writer (A5) **refuses to run** for any slug without `briefs/<slug>.md` marked
|
|
9
|
+
`status: approved`. Rationale: a brief forces real-SERP research, an outline, entities, and a
|
|
10
|
+
unique angle BEFORE generation — which is the difference between a ranked page and generic
|
|
11
|
+
filler. Orchestrator enforces: when dispatching a Writer pane, it verifies the brief exists
|
|
12
|
+
first; if missing, it routes the cluster back to A4, not forward to A5.
|
|
13
|
+
|
|
14
|
+
## Gate 2 — Anti-generic-AI content rules (A5 must obey)
|
|
15
|
+
|
|
16
|
+
BANNED in any generated page:
|
|
17
|
+
- Filler openers: "In today's fast-paced world", "In the digital age", "When it comes to…".
|
|
18
|
+
- Empty hedging: "can help", "may be able to", "is a great way to" with no specifics.
|
|
19
|
+
- Unsupported stats: every number is cited (source + year) or cut.
|
|
20
|
+
- Restated headings as the first sentence of each section.
|
|
21
|
+
- Conclusion that summarizes with no new CTA/next step.
|
|
22
|
+
|
|
23
|
+
REQUIRED in any generated page:
|
|
24
|
+
- ≥1 concrete LeadLyze example or named use-case.
|
|
25
|
+
- ≥1 data table or comparison matrix.
|
|
26
|
+
- Real statistics with citations.
|
|
27
|
+
- An FAQ section answering the People-Also-Ask questions from the brief.
|
|
28
|
+
- Inline internal links from the brief (not dumped at the bottom).
|
|
29
|
+
- A specific CTA tied to the page's funnel stage.
|
|
30
|
+
|
|
31
|
+
## Gate 3 — Thin / duplicate-content gate (programmatic pages)
|
|
32
|
+
|
|
33
|
+
The doorway-page killer. For templated pages each MUST have:
|
|
34
|
+
- Unique `<title>`, `<h1>`, and **first 2 sentences** (keyed off the varying dimension).
|
|
35
|
+
- ≥2 dimension-specific unique blocks (local stat, named local use-case, region-keyed copy).
|
|
36
|
+
- ≥ the cluster's `min_words` floor of genuinely varying text (boilerplate doesn't count).
|
|
37
|
+
- Pairwise similarity < 0.8 vs sibling pages (cheap check: shingle/Jaccard on body text).
|
|
38
|
+
|
|
39
|
+
Fail → `noindex` + queue for enrichment. NEVER ship a city-swap-only page indexable.
|
|
40
|
+
|
|
41
|
+
## Gate 4 — Indexability gate (every page, pre-ship)
|
|
42
|
+
|
|
43
|
+
Before a page moves `linked → shipped`:
|
|
44
|
+
- [ ] Unique title + meta description (≤60 / ≤155 chars), self-referencing canonical.
|
|
45
|
+
- [ ] ≥10 inbound + ≥10 outbound internal links recorded in `link-map.json` (no orphans).
|
|
46
|
+
- [ ] Valid JSON-LD matching page type (A8), validates against schema.org.
|
|
47
|
+
- [ ] Word count ≥ cluster floor; passes Gate 2/3.
|
|
48
|
+
- [ ] No broken internal links (every link target exists in the route set).
|
|
49
|
+
- [ ] `pnpm build` static-generates it; no tsc error introduced.
|
|
50
|
+
|
|
51
|
+
## Gate 5 — Build/type baseline (per wave, orchestrator)
|
|
52
|
+
|
|
53
|
+
Capture `pnpm tsc --noEmit | grep -c "error TS"` at campaign start. After each wave merge,
|
|
54
|
+
re-run; any wave that raises the count is reverted from the integration branch and the
|
|
55
|
+
offending cluster re-dispatched. (Children never run tsc — orchestrator-only, per
|
|
56
|
+
`feedback_no_build_in_child_agents`.)
|
|
57
|
+
|
|
58
|
+
## Gate 6 — Evidence gate (A1/A2/A9/A10)
|
|
59
|
+
|
|
60
|
+
No keyword enters `keywords.csv` without a real Semrush volume+KD. AI-estimated metrics are
|
|
61
|
+
a hypothesis flagged `est=true`, never treated as ground truth, and must be confirmed against
|
|
62
|
+
a live SERP or Semrush pull before a money page is built on them.
|
|
63
|
+
|
|
64
|
+
## What "shipped" means
|
|
65
|
+
|
|
66
|
+
`shipped` = merged into the integration branch, passed Gates 1–6, recorded in `BACKLOG.md`.
|
|
67
|
+
It does **not** mean pushed to master or deployed — that's a separate, explicit,
|
|
68
|
+
user-consented step (see all three skills' push rules).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Weekly Cadence + 90-Day Plan + the A9/A10 Loop
|
|
2
|
+
|
|
3
|
+
The factory has a one-shot ramp (build the backlog of pages) and a steady-state loop (keep
|
|
4
|
+
discovering + refreshing). Both are encoded here. In AUTO mode the orchestrator can run the
|
|
5
|
+
whole week's stages back-to-back across waves; the day labels are the *logical* order, not a
|
|
6
|
+
requirement to wait 24h between them.
|
|
7
|
+
|
|
8
|
+
## Weekly logical order (one full turn of the crank)
|
|
9
|
+
|
|
10
|
+
| Stage | Agents | Output |
|
|
11
|
+
|-------|--------|--------|
|
|
12
|
+
| Research | A1, A10 | competitor pages + net-new keyword opportunities |
|
|
13
|
+
| Expand | A2 | `keywords.csv` grows |
|
|
14
|
+
| Architect | A3 | `clusters.json` updated, new clusters → BACKLOG |
|
|
15
|
+
| Brief | A4 | `briefs/<slug>.md` for the wave's editorial clusters |
|
|
16
|
+
| Write | A5 (fan-out waves) | `src/content/**.mdx` |
|
|
17
|
+
| Interlink | A6 | `link-map.json` ≥10/≥10 per page |
|
|
18
|
+
| Programmatic | A7 + A8 | `src/data/seo/*.ts` + routes + schema |
|
|
19
|
+
| Publish | gates + merge | clusters → `shipped` (push only on consent) |
|
|
20
|
+
| Analyze | A9 | GSC deltas → refresh decaying pages, feed A10 |
|
|
21
|
+
|
|
22
|
+
## 90-day target (state honestly to the user)
|
|
23
|
+
|
|
24
|
+
| Month | Cumulative pages | Emphasis |
|
|
25
|
+
|-------|------------------|----------|
|
|
26
|
+
| 1 | 200 | programmatic location/industry (fast to index) + 20 cornerstone editorial |
|
|
27
|
+
| 2 | 500 | + alternative + comparison money pages |
|
|
28
|
+
| 3 | 1,000+ | + statistics/template/tool/question pages; refresh cycle steady-state |
|
|
29
|
+
|
|
30
|
+
Reality check to set with the user: programmatic pages can index in **weeks**; cornerstone
|
|
31
|
+
editorial is a **60–180 day** payoff. New content rarely ranks in 30 days. Don't promise
|
|
32
|
+
rankings on a 30-day horizon — promise *production throughput* + a compounding curve.
|
|
33
|
+
|
|
34
|
+
## The recurring loop (A9 + A10 — never "done")
|
|
35
|
+
|
|
36
|
+
These are cron-shaped. Under `/loop` or `/schedule`, the orchestrator wakes them:
|
|
37
|
+
|
|
38
|
+
**A10 Opportunity Finder — daily**
|
|
39
|
+
1. Semrush `organic_research` diff: keywords competitors now rank for that aren't in `keywords.csv`.
|
|
40
|
+
2. Score: `volume × intent_weight × winnability`. Dedupe vs existing keywords.
|
|
41
|
+
3. Auto-brief the top N → append clusters to `BACKLOG.md` as `pending`.
|
|
42
|
+
4. Next fan-out wave picks them up. No human in the loop unless a money cluster needs sign-off.
|
|
43
|
+
|
|
44
|
+
**A9 Content Refresh — weekly**
|
|
45
|
+
1. Pull `gsc-deltas.csv` (pages with falling position over 28 days) via browser-harness/GSC.
|
|
46
|
+
2. For each decayer: diff vs current top-3 SERP. Update stale stats, add new competitors,
|
|
47
|
+
add fresh internal links + examples, bump `dateModified`.
|
|
48
|
+
3. Record the diff; re-run gates; mark refreshed.
|
|
49
|
+
|
|
50
|
+
## Backlog states (the frontier)
|
|
51
|
+
|
|
52
|
+
`BACKLOG.md` tracks each cluster through: `pending → briefed → written → linked → shipped`
|
|
53
|
+
(+ `noindex` for gate failures awaiting enrichment). This is the durable memory that
|
|
54
|
+
survives auto-compact — the orchestrator always resumes from the file, never from chat
|
|
55
|
+
recollection. Commit it at Phase 0 and after every wave.
|
|
56
|
+
|
|
57
|
+
## Heartbeat honesty (inherited from autonomous-fix-campaign)
|
|
58
|
+
|
|
59
|
+
`ScheduleWakeup` only fires under `/loop`. Outside it, saying "I'll wake in 20 min" is a lie.
|
|
60
|
+
At Phase 0 confirm the heartbeat path with the user — `/loop`, `/schedule` cron, or manual
|
|
61
|
+
ping — and act accordingly. Never go silent while panes are `working`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# SEO Content Factory — BACKLOG (durable frontier)
|
|
2
|
+
# Commit at Phase 0 and after every wave. The orchestrator resumes from THIS file,
|
|
3
|
+
# never from chat memory. States: pending → briefed → written → linked → shipped (+ noindex).
|
|
4
|
+
|
|
5
|
+
## Campaign config
|
|
6
|
+
- target_site: /home/hanzla/development/teaching/schedule-manager/marketing
|
|
7
|
+
- integration_branch: seo-factory-integration
|
|
8
|
+
- tsc_baseline: <fill: `pnpm tsc --noEmit | grep -c "error TS"`>
|
|
9
|
+
- push_policy: LOCAL ONLY — no push/deploy without explicit user consent
|
|
10
|
+
- heartbeat: <fill: /loop | /schedule cron | manual ping>
|
|
11
|
+
- seeds: ["lead generation software", "cold email", "ai cold calling", "sales sequences"]
|
|
12
|
+
- competitors: ["apollo.io", "instantly.ai", "lemlist.com", "smartlead.ai"]
|
|
13
|
+
|
|
14
|
+
## Clusters
|
|
15
|
+
| cluster_id | hub | page_kind | spokes | state | wave | notes |
|
|
16
|
+
|---|---|---|---|---|---|---|
|
|
17
|
+
| alt-apollo | alternatives | editorial | 1 | pending | – | money page |
|
|
18
|
+
| ind-roofers | lead-generation | editorial | 1 | pending | – | |
|
|
19
|
+
| loc-grid | lead-generation×city | programmatic | 2000 | pending | – | 100 cities × 20 services |
|
|
20
|
+
| stat-coldemail | statistics | editorial | 1 | pending | – | linkable asset |
|
|
21
|
+
|
|
22
|
+
## Wave log
|
|
23
|
+
<!-- append: wave N | clusters | merged SHA | pages shipped | tsc delta -->
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Funnel prompts (A1→A4) — run SEQUENTIALLY, one agent, before any fan-out.
|
|
2
|
+
|
|
3
|
+
Common footer appended to EVERY prompt below:
|
|
4
|
+
> Pull REAL data from Semrush MCP / live SERP before asserting any number — never invent volume/KD/traffic.
|
|
5
|
+
> Write output to the canonical file path under `.planning/seo-factory/`. Do not print results only to chat.
|
|
6
|
+
> You are working in the `marketing/` repo. Commit your output file with a clear message.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## A1 — Competitor Research
|
|
11
|
+
```
|
|
12
|
+
You are an SEO competitor analyst for LeadLyze (a lead-generation / sales-outreach platform:
|
|
13
|
+
email + LinkedIn + AI cold calling sequences).
|
|
14
|
+
|
|
15
|
+
Competitors: apollo.io, instantly.ai, lemlist.com, smartlead.ai.
|
|
16
|
+
|
|
17
|
+
Using Semrush MCP (organic_research, overview_research) + web search, for EACH competitor pull
|
|
18
|
+
their highest-traffic organic pages. For each page produce a CSV row:
|
|
19
|
+
keyword,type,intent,traffic,funnel,source_url,competitor
|
|
20
|
+
- type ∈ industry | location | alternative | comparison | statistics | template | tool | blog
|
|
21
|
+
- intent ∈ informational | commercial | transactional | navigational
|
|
22
|
+
- funnel ∈ learn | compare | buy
|
|
23
|
+
Keep only rows where LeadLyze could plausibly compete. ≥200 rows.
|
|
24
|
+
Write to .planning/seo-factory/competitors.csv.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## A2 — Keyword Expansion
|
|
28
|
+
```
|
|
29
|
+
Read .planning/seo-factory/competitors.csv. Seeds: "lead generation software", "cold email",
|
|
30
|
+
"ai cold calling", "sales sequences".
|
|
31
|
+
|
|
32
|
+
Expand every seed across all 8 modifier axes: industry, location, alternative, comparison,
|
|
33
|
+
template, statistics, question, tool. Use Semrush keyword_research (related + questions +
|
|
34
|
+
broad match) to pull REAL volume and KD for each. Drop volume<10 OR KD>70 unless it is a clear
|
|
35
|
+
money term. De-dupe. Thousands of rows.
|
|
36
|
+
Write to .planning/seo-factory/keywords.csv with columns:
|
|
37
|
+
keyword,parent_seed,modifier_type,volume,kd,intent,funnel,cluster_id (leave cluster_id blank)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## A3 — Sitemap Architect
|
|
41
|
+
```
|
|
42
|
+
Read .planning/seo-factory/keywords.csv. Cluster keywords by SERP overlap (use the
|
|
43
|
+
claude-seo:seo-cluster skill / serp-analysis) into hub-and-spoke topics.
|
|
44
|
+
|
|
45
|
+
For each cluster decide page_kind:
|
|
46
|
+
- programmatic = high-volume templated dimensions (service×city, service×industry) → declare dimensions
|
|
47
|
+
- editorial = where prose ranks (alternatives, comparisons, cornerstone, statistics)
|
|
48
|
+
Mark each spoke type (money|supporting|blog) and min_words.
|
|
49
|
+
Write .planning/seo-factory/clusters.json (validate against templates/cluster.schema.json) and
|
|
50
|
+
write each keyword's cluster_id back into keywords.csv. Append new clusters to BACKLOG.md as pending.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## A4 — Content Brief Generator (the GATE feeder)
|
|
54
|
+
```
|
|
55
|
+
Read .planning/seo-factory/clusters.json. For EACH editorial cluster (skip programmatic ones),
|
|
56
|
+
read the LIVE top-5 Google results for its primary keyword (serp-analysis) and produce a brief
|
|
57
|
+
following templates/content-brief.md EXACTLY:
|
|
58
|
+
title, meta, search intent, full H2/H3 outline (mirror the winning structure + 1 unique
|
|
59
|
+
LeadLyze angle the top-5 lack), FAQ from People-Also-Ask, entities, inline internal links,
|
|
60
|
+
CTA, schema types, min_words.
|
|
61
|
+
Write each to .planning/seo-factory/briefs/<slug>.md with status: approved.
|
|
62
|
+
Do NOT write any article — briefs only. Mark each cluster `briefed` in BACKLOG.md.
|
|
63
|
+
```
|
package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/02-fanout-editorial-A5-A6-A8.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Fan-out pane prompt — EDITORIAL cluster (runs A5→A6→A8 in one worktree).
|
|
2
|
+
# One pane per cluster. Orchestrator fills {{CLUSTER_ID}}, {{BRANCH}}, {{SLUGS}}.
|
|
3
|
+
|
|
4
|
+
```
|
|
5
|
+
You are an SEO content agent in an ISOLATED git worktree on branch {{BRANCH}}, inside the
|
|
6
|
+
LeadLyze `marketing/` repo. Work and commit ONLY here. Do NOT run pnpm build / tsc / dev /
|
|
7
|
+
install — use `node --check` only. Do NOT push.
|
|
8
|
+
|
|
9
|
+
Your cluster: {{CLUSTER_ID}}. Its approved briefs: {{SLUGS}} (under .planning/seo-factory/briefs/).
|
|
10
|
+
|
|
11
|
+
GATE: For each slug, confirm .planning/seo-factory/briefs/<slug>.md exists with status: approved.
|
|
12
|
+
If a brief is missing, STOP that slug and report it — never write an article without a brief.
|
|
13
|
+
|
|
14
|
+
For each slug:
|
|
15
|
+
1. (A5 Writer) Write src/content/<type>/<slug>.mdx STRICTLY to its brief, using
|
|
16
|
+
templates/article.mdx frontmatter. MANDATORY quality rules (quality-gates.md Gate 2):
|
|
17
|
+
- real LeadLyze examples + named use-cases, ≥1 data table, cited statistics, FAQ section
|
|
18
|
+
- inline internal links from the brief (not dumped at bottom), funnel-matched CTA
|
|
19
|
+
- BANNED: "in today's fast-paced world", empty hedging, uncited numbers, restated headings.
|
|
20
|
+
2. (A6 Interlinker) Add ≥10 inbound + ≥10 outbound internal links with KEYWORD-VARIED anchors
|
|
21
|
+
(never the same anchor twice). Prefer same-cluster + hub↔spoke. Record in
|
|
22
|
+
.planning/seo-factory/link-map.json (write ONLY your cluster's keys).
|
|
23
|
+
3. (A8 Schema) Inject JSON-LD via src/lib/jsonld.ts builders (FAQPage + the page's type +
|
|
24
|
+
BreadcrumbList). No hand-written <script> strings.
|
|
25
|
+
|
|
26
|
+
Commit each page separately. Log what you shipped to .planning/seo-factory/AUDIT-{{CLUSTER_ID}}.md
|
|
27
|
+
(page list, word counts, link counts). When done, give a one-line recap.
|
|
28
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Fan-out pane prompt — PROGRAMMATIC cluster (runs A7→A6→A8 in one worktree).
|
|
2
|
+
# Skips the Writer (no per-page prose). Orchestrator fills {{CLUSTER_ID}}, {{BRANCH}}, {{DIMENSIONS}}.
|
|
3
|
+
|
|
4
|
+
```
|
|
5
|
+
You are a programmatic-SEO agent in an ISOLATED git worktree on branch {{BRANCH}}, inside the
|
|
6
|
+
LeadLyze `marketing/` repo. Work and commit ONLY here. Do NOT run pnpm build / tsc / dev /
|
|
7
|
+
install — `node --check` only. Do NOT push.
|
|
8
|
+
|
|
9
|
+
Cluster: {{CLUSTER_ID}}. Dimensions: {{DIMENSIONS}} (e.g. service × city → services.ts × cities.ts).
|
|
10
|
+
|
|
11
|
+
1. (A7) Build/extend the typed registries under src/data/seo/ (e.g. services.ts, cities.ts,
|
|
12
|
+
industries.ts) — typed TS exports matching the existing src/data/*.ts convention. Populate
|
|
13
|
+
real records (real city names/regions; real service benefits/painPoints/faqs from the cluster).
|
|
14
|
+
2. (A7) Create/confirm ONE dynamic route per pattern under src/app/(seo)/... using
|
|
15
|
+
generateStaticParams over the cross-product (see templates/programmatic-page.tsx). 100×20 = 2000
|
|
16
|
+
pages from ~5 files — never 2000 separate files.
|
|
17
|
+
THIN-CONTENT GATE (quality-gates.md Gate 3): every page MUST inject ≥2 dimension-specific
|
|
18
|
+
unique blocks (region-keyed intro, local stat, named local use-case). A pure city-swap page
|
|
19
|
+
is a doorway page — forbidden. Keyword-vary the title, H1, and first 2 sentences.
|
|
20
|
+
3. (A6) Wire hub↔spoke + cross-links; record your cluster's keys in link-map.json.
|
|
21
|
+
4. (A8) Add typed JSON-LD builders to src/lib/jsonld.ts for this page type; render via <JsonLd/>.
|
|
22
|
+
|
|
23
|
+
`node --check` every touched .ts/.tsx. Commit. Log page count + sample slugs to
|
|
24
|
+
.planning/seo-factory/AUDIT-{{CLUSTER_ID}}.md. One-line recap when done.
|
|
25
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Loop prompts (A9 weekly, A10 daily) — the recurring engine. Never "done".
|
|
2
|
+
|
|
3
|
+
Common footer:
|
|
4
|
+
> Pull REAL data (Semrush / GSC / live SERP). Write to canonical files. Dedupe against existing.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## A10 — Opportunity Finder (daily)
|
|
9
|
+
```
|
|
10
|
+
You are an SEO opportunity scout for LeadLyze. Competitors: apollo.io, instantly.ai,
|
|
11
|
+
lemlist.com, smartlead.ai.
|
|
12
|
+
|
|
13
|
+
Using Semrush organic_research, find keywords competitors NOW rank for that are NOT in
|
|
14
|
+
.planning/seo-factory/keywords.csv (diff vs the file). Score each by volume × intent_weight ×
|
|
15
|
+
winnability (lower KD + topical fit = higher). Dedupe against keywords.csv.
|
|
16
|
+
|
|
17
|
+
For the top N: append them to keywords.csv, create cluster stubs, and append those clusters to
|
|
18
|
+
BACKLOG.md as `pending` so the next fan-out wave picks them up. For money clusters, flag for
|
|
19
|
+
human sign-off rather than auto-shipping. Report the top opportunities with scores.
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## A9 — Content Refresh (weekly)
|
|
23
|
+
```
|
|
24
|
+
You are an SEO refresh agent for LeadLyze. Read .planning/seo-factory/gsc-deltas.csv (pages
|
|
25
|
+
whose position fell over the last 28 days; pull via browser-harness/GSC if the file is stale).
|
|
26
|
+
|
|
27
|
+
For each decaying page:
|
|
28
|
+
1. Diff the page against the CURRENT top-3 Google results (serp-analysis).
|
|
29
|
+
2. Update stale statistics (re-cite), add newly-relevant competitors/examples, add fresh
|
|
30
|
+
internal links, and bump dateModified in the frontmatter.
|
|
31
|
+
3. Re-run the indexability gate (quality-gates.md Gate 4). Record the diff (what changed +
|
|
32
|
+
why) to .planning/seo-factory/AUDIT-refresh.md.
|
|
33
|
+
Do NOT rewrite pages wholesale — incremental refresh only. Commit each page separately.
|
|
34
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
# A5 output frontmatter — keep keys stable; the MDX loader + schema (A8) read these.
|
|
3
|
+
title: "The Best Apollo Alternative in 2026: LeadLyze vs Apollo"
|
|
4
|
+
description: "Looking for an Apollo alternative? See how LeadLyze beats Apollo on price, deliverability, and AI outreach."
|
|
5
|
+
slug: apollo-alternative
|
|
6
|
+
cluster_id: alt-apollo
|
|
7
|
+
type: alternatives # blog | alternatives | comparisons → maps to src/content/<type>/
|
|
8
|
+
keyword: apollo alternative
|
|
9
|
+
intent: commercial
|
|
10
|
+
published: 2026-06-14
|
|
11
|
+
dateModified: 2026-06-14
|
|
12
|
+
schema: [SoftwareApplication, FAQPage, BreadcrumbList]
|
|
13
|
+
internalLinks:
|
|
14
|
+
- { to: instantly-alternative, anchor: "compared to Instantly" }
|
|
15
|
+
- { to: ai-cold-calling, anchor: "AI cold calling" }
|
|
16
|
+
- { to: pricing, anchor: "LeadLyze pricing" }
|
|
17
|
+
faq:
|
|
18
|
+
- q: "Is there a free Apollo alternative?"
|
|
19
|
+
a: "Yes — LeadLyze offers a free tier that includes…"
|
|
20
|
+
- q: "Can I import my Apollo data into LeadLyze?"
|
|
21
|
+
a: "Yes, via CSV or the migration importer…"
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
{/* Body: written STRICTLY to briefs/apollo-alternative.md. Obeys quality-gates.md Gate 2.
|
|
25
|
+
No "in today's fast-paced world". Real table. Cited stats. Inline internal links. */}
|
|
26
|
+
|
|
27
|
+
Sales teams switch off Apollo for three concrete reasons: per-credit pricing that scales
|
|
28
|
+
badly, [deliverability complaints](/blog/cold-email-deliverability), and no native dialer.
|
|
29
|
+
Here's how LeadLyze handles each.
|
|
30
|
+
|
|
31
|
+
## LeadLyze vs Apollo — side by side
|
|
32
|
+
|
|
33
|
+
| Capability | Apollo | LeadLyze |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| AI cold calling | ❌ | ✅ |
|
|
36
|
+
| Email + LinkedIn sequences | ✅ | ✅ |
|
|
37
|
+
| Per-credit pricing | Yes | Flat seats |
|
|
38
|
+
|
|
39
|
+
<!-- … rest of body per brief outline … -->
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "clusters.json — A3 output",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["hubs"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"hubs": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"required": ["id", "title", "hub_page", "spokes", "page_kind"],
|
|
12
|
+
"properties": {
|
|
13
|
+
"id": { "type": "string" },
|
|
14
|
+
"title": { "type": "string" },
|
|
15
|
+
"hub_page": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"required": ["slug", "type", "keyword"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"slug": { "type": "string" },
|
|
20
|
+
"type": { "enum": ["money", "supporting", "blog"] },
|
|
21
|
+
"keyword": { "type": "string" }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"page_kind": { "enum": ["programmatic", "editorial"] },
|
|
25
|
+
"dimensions": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"description": "Required when page_kind=programmatic",
|
|
28
|
+
"properties": {
|
|
29
|
+
"service": { "type": "string" },
|
|
30
|
+
"vary_by": { "type": "string", "description": "registry file e.g. industries.ts" }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"spokes": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"required": ["slug", "type", "keyword", "page_kind", "min_words", "cluster_id"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"slug": { "type": "string" },
|
|
40
|
+
"type": { "enum": ["money", "supporting", "blog"] },
|
|
41
|
+
"keyword": { "type": "string" },
|
|
42
|
+
"page_kind": { "enum": ["programmatic", "editorial"] },
|
|
43
|
+
"min_words": { "type": "integer", "minimum": 600 },
|
|
44
|
+
"cluster_id": { "type": "string" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
# A4 output — the brief-before-prose GATE artifact.
|
|
3
|
+
# A5 Writer REFUSES to run unless this file exists and status: approved.
|
|
4
|
+
slug: apollo-alternative
|
|
5
|
+
cluster_id: alt-apollo
|
|
6
|
+
type: money # money | supporting | blog
|
|
7
|
+
keyword: apollo alternative
|
|
8
|
+
secondary_keywords: [apollo io alternative, apollo competitor, cheaper than apollo]
|
|
9
|
+
intent: commercial # informational | commercial | transactional | navigational
|
|
10
|
+
funnel: buy # learn | compare | buy
|
|
11
|
+
min_words: 1600
|
|
12
|
+
schema: [SoftwareApplication, FAQPage, BreadcrumbList]
|
|
13
|
+
status: approved # draft | approved
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Title (≤60 chars, keyword-leading)
|
|
17
|
+
The Best Apollo Alternative in 2026: LeadLyze vs Apollo
|
|
18
|
+
|
|
19
|
+
# Meta description (≤155 chars)
|
|
20
|
+
Looking for an Apollo alternative? See how LeadLyze beats Apollo on price, deliverability, and AI outreach — with a side-by-side breakdown.
|
|
21
|
+
|
|
22
|
+
# Search intent (one paragraph from the live top-5 SERP)
|
|
23
|
+
Buyers comparing tools; want a concrete feature+price comparison and a reason to switch, not a generic listicle. Top-5 are all comparison pages with tables.
|
|
24
|
+
|
|
25
|
+
# Outline (mirror the winning SERP structure + 1 unique angle)
|
|
26
|
+
## H2: Why teams look for an Apollo alternative
|
|
27
|
+
### H3: Pricing pain points
|
|
28
|
+
### H3: Deliverability / data accuracy complaints
|
|
29
|
+
## H2: LeadLyze vs Apollo — side by side ← REQUIRED data table
|
|
30
|
+
## H2: Feature-by-feature breakdown
|
|
31
|
+
### H3: AI cold calling (LeadLyze unique angle — Apollo lacks this)
|
|
32
|
+
## H2: Pricing comparison ← REQUIRED table
|
|
33
|
+
## H2: When Apollo is still the better choice (honesty builds trust)
|
|
34
|
+
## H2: How to migrate from Apollo to LeadLyze
|
|
35
|
+
|
|
36
|
+
# Entities to cover (from top-5 + gap analysis)
|
|
37
|
+
email deliverability, data enrichment, sequences, CRM sync, credits model, AI dialer, GDPR
|
|
38
|
+
|
|
39
|
+
# FAQ (from People-Also-Ask — becomes FAQPage schema)
|
|
40
|
+
- Is there a free Apollo alternative?
|
|
41
|
+
- Is LeadLyze cheaper than Apollo?
|
|
42
|
+
- Can I import my Apollo data into LeadLyze?
|
|
43
|
+
- Which has better email deliverability?
|
|
44
|
+
|
|
45
|
+
# Internal links (inject inline, not at the bottom)
|
|
46
|
+
- → /instantly-alternative (anchor: "compared to Instantly")
|
|
47
|
+
- → /ai-cold-calling (anchor: "AI cold calling")
|
|
48
|
+
- → /pricing (anchor: "LeadLyze pricing")
|
|
49
|
+
|
|
50
|
+
# CTA (funnel: buy)
|
|
51
|
+
"Start free — migrate your Apollo lists in minutes." → /signup
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// A8 — extend the EXISTING src/lib/jsonld.ts with these typed builders.
|
|
2
|
+
// Render via a <JsonLd data={...} /> component, never hand-written <script> strings.
|
|
3
|
+
// Do not duplicate if equivalents already exist in src/lib/jsonld.ts — extend, don't fork.
|
|
4
|
+
|
|
5
|
+
export function softwareApplication() {
|
|
6
|
+
return {
|
|
7
|
+
'@context': 'https://schema.org',
|
|
8
|
+
'@type': 'SoftwareApplication',
|
|
9
|
+
name: 'LeadLyze',
|
|
10
|
+
applicationCategory: 'BusinessApplication',
|
|
11
|
+
operatingSystem: 'Web',
|
|
12
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
|
|
13
|
+
aggregateRating: { '@type': 'AggregateRating', ratingValue: '4.8', reviewCount: '120' },
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function faqPage(faqs: { q: string; a: string }[]) {
|
|
18
|
+
return {
|
|
19
|
+
'@context': 'https://schema.org',
|
|
20
|
+
'@type': 'FAQPage',
|
|
21
|
+
mainEntity: faqs.map((f) => ({
|
|
22
|
+
'@type': 'Question',
|
|
23
|
+
name: f.q,
|
|
24
|
+
acceptedAnswer: { '@type': 'Answer', text: f.a },
|
|
25
|
+
})),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function breadcrumbList(items: { name: string; url: string }[]) {
|
|
30
|
+
return {
|
|
31
|
+
'@context': 'https://schema.org',
|
|
32
|
+
'@type': 'BreadcrumbList',
|
|
33
|
+
itemListElement: items.map((it, i) => ({
|
|
34
|
+
'@type': 'ListItem',
|
|
35
|
+
position: i + 1,
|
|
36
|
+
name: it.name,
|
|
37
|
+
item: `https://leadlyze.com${it.url}`,
|
|
38
|
+
})),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function product(name: string, rating = '4.8', reviews = '120') {
|
|
43
|
+
return {
|
|
44
|
+
'@context': 'https://schema.org',
|
|
45
|
+
'@type': 'Product',
|
|
46
|
+
name,
|
|
47
|
+
aggregateRating: { '@type': 'AggregateRating', ratingValue: rating, reviewCount: reviews },
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
keyword,parent_seed,modifier_type,volume,kd,intent,funnel,cluster_id
|
|
2
|
+
lead generation for dentists,lead generation software,industry,720,34,commercial,buy,ind-dentists
|
|
3
|
+
lead generation for roofers,lead generation software,industry,590,29,commercial,buy,ind-roofers
|
|
4
|
+
lead generation for lawyers,lead generation software,industry,880,41,commercial,buy,ind-lawyers
|
|
5
|
+
lead generation dubai,lead generation software,location,480,22,commercial,buy,loc-dubai
|
|
6
|
+
lead generation london,lead generation software,location,1300,38,commercial,buy,loc-london
|
|
7
|
+
apollo alternative,lead generation software,alternative,2900,61,commercial,buy,alt-apollo
|
|
8
|
+
instantly alternative,cold email,alternative,1600,48,commercial,buy,alt-instantly
|
|
9
|
+
apollo vs leadlyze,lead generation software,comparison,90,12,commercial,compare,cmp-apollo
|
|
10
|
+
cold email templates,cold email,template,5400,52,informational,learn,tpl-coldemail
|
|
11
|
+
cold email open rate statistics,cold email,statistics,1300,18,informational,learn,stat-coldemail
|
|
12
|
+
how to generate leads for saas,lead generation software,question,210,27,informational,learn,q-saas
|
|
13
|
+
free lead generation tool,lead generation software,tool,1900,55,transactional,buy,tool-leadgen
|