Skip to content

Commit a8edcc3

Browse files
rubenmarcusclaudegreptile-apps[bot]
authored
docs: add SEO marketing plan and full docs.md generator (#186)
* docs: add SEO marketing plan and full docs.md generator - Add comprehensive SEO & marketing strategy doc with 35+ article roadmap, 4-tier keyword strategy, and social media playbook - Add build script to generate a single docs.md from all 39 doc pages - Hook script into docs build so docs.md stays up to date - Serve at /docs.md for easy single-file download Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(docs): add download docs button with .md and .txt options Adds a DownloadDocs component to the docs intro page with two download buttons: .md (full formatted docs) and .txt (llms-full.txt). Styled to match the quantum theme. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update docs/scripts/generate-full-docs.cjs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(docs): skip fenced code blocks when bumping headings The heading bumper was running on every line including fenced code blocks, turning shell comments like "# Install" into "## Install". Now tracks fence state and only bumps actual markdown headings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent 85ece6b commit a8edcc3

File tree

7 files changed

+9214
-1
lines changed

7 files changed

+9214
-1
lines changed

docs/SEO_MARKETING_PLAN.md

Lines changed: 908 additions & 0 deletions
Large diffs are not rendered by default.

docs/docs/intro.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ keywords: [ralph wiggum, autonomous coding, AI coding loops, claude code]
99

1010
> **Ralph Wiggum made easy.** One command to run autonomous AI coding loops.
1111
12+
import DownloadDocs from '@site/src/components/DownloadDocs'
13+
14+
<DownloadDocs />
15+
1216
## What is Ralph Wiggum?
1317

1418
Ralph Wiggum is a technique for running AI coding agents in autonomous loops until tasks are completed. Instead of prompting back and forth, you give the AI a task and let it iterate until done.

docs/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"scripts": {
66
"docusaurus": "docusaurus",
77
"start": "docusaurus start",
8-
"build": "docusaurus build",
8+
"build": "node scripts/generate-full-docs.cjs && docusaurus build",
9+
"docs:full": "node scripts/generate-full-docs.cjs",
910
"seo:check": "node scripts/check-seo-aeo.cjs",
1011
"seo:sync": "node scripts/sync-seo-aeo-assets.cjs",
1112
"swizzle": "docusaurus swizzle",
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* Generates a single markdown file containing all ralph-starter documentation.
3+
* Output: docs/static/docs.md
4+
*
5+
* Usage: node scripts/generate-full-docs.cjs
6+
*/
7+
8+
const fs = require('fs');
9+
const path = require('path');
10+
11+
const DOCS_DIR = path.join(__dirname, '..', 'docs');
12+
const OUTPUT_FILE = path.join(__dirname, '..', 'static', 'docs.md');
13+
14+
// Ordered sections matching the sidebar structure
15+
const SECTIONS = [
16+
{ heading: 'Getting Started', files: ['intro.md', 'installation.md'] },
17+
{
18+
heading: 'CLI Commands',
19+
dir: 'cli',
20+
files: [
21+
'run.md',
22+
'auto.md',
23+
'init.md',
24+
'plan.md',
25+
'setup.md',
26+
'check.md',
27+
'config.md',
28+
'auth.md',
29+
'integrations.md',
30+
'source.md',
31+
'presets.md',
32+
'skill.md',
33+
'template.md',
34+
],
35+
},
36+
{
37+
heading: 'Sources & Integrations',
38+
dir: 'sources',
39+
files: ['overview.md', 'github.md', 'linear.md', 'notion.md', 'figma.md'],
40+
},
41+
{
42+
heading: 'Guides',
43+
dir: 'guides',
44+
files: [
45+
'workflow-presets.md',
46+
'prd-workflow.md',
47+
'cost-tracking.md',
48+
'skills-system.md',
49+
'testing-integrations.md',
50+
'extending-ralph-starter.md',
51+
],
52+
},
53+
{
54+
heading: 'Wizard',
55+
dir: 'wizard',
56+
files: ['overview.md', 'idea-mode.md'],
57+
},
58+
{
59+
heading: 'Advanced',
60+
dir: 'advanced',
61+
files: [
62+
'validation.md',
63+
'git-automation.md',
64+
'circuit-breaker.md',
65+
'rate-limiting.md',
66+
'ralph-playbook.md',
67+
],
68+
},
69+
{
70+
heading: 'MCP Server',
71+
dir: 'mcp',
72+
files: ['setup.md', 'claude-desktop.md'],
73+
},
74+
{
75+
heading: 'Community',
76+
dir: 'community',
77+
files: ['contributing.md', 'changelog.md', 'ideas.md'],
78+
},
79+
{ heading: 'FAQ', files: ['faq.md'] },
80+
];
81+
82+
function stripFrontmatter(content) {
83+
if (content.startsWith('---')) {
84+
const end = content.indexOf('---', 3);
85+
if (end !== -1) {
86+
return content.slice(end + 3).trimStart();
87+
}
88+
}
89+
return content;
90+
}
91+
92+
function bumpHeadings(content) {
93+
// Bump all headings down by one level (# -> ##, ## -> ###, etc.)
94+
// so section headings stay as the top-level within each section.
95+
// Skip lines inside fenced code blocks to avoid mutating snippets
96+
// (e.g. shell comments like "# Install" should not become "## Install").
97+
const lines = content.split('\n');
98+
let inFence = false;
99+
100+
for (let i = 0; i < lines.length; i++) {
101+
if (/^```/.test(lines[i])) {
102+
inFence = !inFence;
103+
continue;
104+
}
105+
if (!inFence) {
106+
lines[i] = lines[i].replace(/^(#{1,5}) /, (_, hashes) => hashes + '# ');
107+
}
108+
}
109+
110+
return lines.join('\n');
111+
}
112+
113+
function generate() {
114+
const parts = [];
115+
116+
parts.push('# ralph-starter Documentation\n');
117+
parts.push(
118+
'> AI-powered autonomous coding tool. Connect GitHub, Linear, Notion, Figma and run AI coding loops from specs to production.\n'
119+
);
120+
parts.push(
121+
`> Generated on ${new Date().toISOString().split('T')[0]} | [ralphstarter.ai](https://ralphstarter.ai)\n`
122+
);
123+
124+
// Table of contents
125+
parts.push('## Table of Contents\n');
126+
for (const section of SECTIONS) {
127+
parts.push(`- [${section.heading}](#${section.heading.toLowerCase().replace(/[^a-z0-9]+/g, '-')})`);
128+
}
129+
parts.push('');
130+
131+
parts.push('---\n');
132+
133+
for (const section of SECTIONS) {
134+
parts.push(`## ${section.heading}\n`);
135+
136+
for (const file of section.files) {
137+
const filePath = section.dir
138+
? path.join(DOCS_DIR, section.dir, file)
139+
: path.join(DOCS_DIR, file);
140+
141+
if (!fs.existsSync(filePath)) {
142+
console.warn(`Warning: ${filePath} not found, skipping`);
143+
continue;
144+
}
145+
146+
const raw = fs.readFileSync(filePath, 'utf-8');
147+
const content = bumpHeadings(stripFrontmatter(raw));
148+
parts.push(content);
149+
parts.push('\n---\n');
150+
}
151+
}
152+
153+
const output = parts.join('\n');
154+
fs.writeFileSync(OUTPUT_FILE, output, 'utf-8');
155+
156+
const lines = output.split('\n').length;
157+
const sizeKb = (Buffer.byteLength(output, 'utf-8') / 1024).toFixed(1);
158+
console.log(`Generated ${OUTPUT_FILE}`);
159+
console.log(` ${lines} lines, ${sizeKb} KB`);
160+
}
161+
162+
generate();
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { ReactNode } from 'react';
2+
import styles from './styles.module.css';
3+
4+
export default function DownloadDocs(): ReactNode {
5+
return (
6+
<div className={styles.wrapper}>
7+
<div className={styles.card}>
8+
<div className={styles.icon}>
9+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
10+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
11+
<polyline points="7 10 12 15 17 10" />
12+
<line x1="12" y1="15" x2="12" y2="3" />
13+
</svg>
14+
</div>
15+
<div className={styles.content}>
16+
<span className={styles.title}>Download full docs</span>
17+
<span className={styles.subtitle}>All 39 pages in a single file</span>
18+
</div>
19+
<div className={styles.buttons}>
20+
<a
21+
href="/docs.md"
22+
download="ralph-starter-docs.md"
23+
className={styles.button}
24+
>
25+
.md
26+
</a>
27+
<a
28+
href="/llms-full.txt"
29+
download="ralph-starter-docs.txt"
30+
className={styles.button}
31+
>
32+
.txt
33+
</a>
34+
</div>
35+
</div>
36+
</div>
37+
);
38+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
.wrapper {
2+
margin: 1.5rem 0;
3+
}
4+
5+
.card {
6+
display: flex;
7+
align-items: center;
8+
gap: 0.75rem;
9+
padding: 0.75rem 1rem;
10+
background: var(--quantum-surface);
11+
border: 1px solid var(--quantum-tungsten);
12+
border-radius: var(--radius-md);
13+
transition: border-color 0.2s ease;
14+
}
15+
16+
.card:hover {
17+
border-color: var(--quantum-steel);
18+
}
19+
20+
.icon {
21+
display: flex;
22+
align-items: center;
23+
justify-content: center;
24+
color: var(--quantum-silver);
25+
flex-shrink: 0;
26+
}
27+
28+
.content {
29+
display: flex;
30+
flex-direction: column;
31+
flex: 1;
32+
min-width: 0;
33+
}
34+
35+
.title {
36+
font-family: var(--font-body);
37+
font-size: 0.875rem;
38+
font-weight: 600;
39+
color: var(--quantum-white);
40+
line-height: 1.3;
41+
}
42+
43+
.subtitle {
44+
font-family: var(--font-body);
45+
font-size: 0.75rem;
46+
color: var(--quantum-silver);
47+
line-height: 1.3;
48+
}
49+
50+
.buttons {
51+
display: flex;
52+
gap: 0.5rem;
53+
flex-shrink: 0;
54+
}
55+
56+
.button {
57+
font-family: var(--font-mono);
58+
font-size: 0.75rem;
59+
font-weight: 600;
60+
padding: 0.375rem 0.75rem;
61+
border: 1px solid var(--quantum-tungsten);
62+
border-radius: var(--radius-sm);
63+
background: transparent;
64+
color: var(--quantum-light);
65+
text-decoration: none;
66+
transition: all 0.2s ease;
67+
white-space: nowrap;
68+
}
69+
70+
.button:hover {
71+
border-color: var(--quantum-mist);
72+
background: rgba(152, 152, 159, 0.08);
73+
color: var(--quantum-white);
74+
text-decoration: none;
75+
}
76+
77+
@media screen and (max-width: 500px) {
78+
.card {
79+
flex-wrap: wrap;
80+
}
81+
82+
.buttons {
83+
width: 100%;
84+
justify-content: flex-end;
85+
}
86+
}

0 commit comments

Comments
 (0)