anymorph 0.4.0 → 0.6.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/README.md +3 -3
- package/dist/index.js +79 -6
- package/package.json +1 -1
- package/dist/skillpacks/geo/scaffold/AGENTS.md +0 -38
- package/dist/skillpacks/geo/scaffold/CLAUDE.md +0 -33
- package/dist/skillpacks/geo/shared/evidence-principles.md +0 -35
- package/dist/skillpacks/geo/shared/geo-principles.md +0 -281
- package/dist/skillpacks/geo/shared/vertical-playbooks/beauty.md +0 -65
- package/dist/skillpacks/geo/shared/vertical-playbooks/commerce.md +0 -65
- package/dist/skillpacks/geo/shared/vertical-playbooks/ota.md +0 -62
- package/dist/skillpacks/geo/shared/vertical-playbooks/saas.md +0 -64
- package/dist/skillpacks/geo/skills/brand-owned-diagnosis/SKILL.md +0 -54
- package/dist/skillpacks/geo/skills/brand-owned-diagnosis/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/brand-owned-diagnosis/references/diagnosis-contract.md +0 -95
- package/dist/skillpacks/geo/skills/brand-owned-diagnosis/references/workflow.md +0 -194
- package/dist/skillpacks/geo/skills/geo-generating-actions/SKILL.md +0 -188
- package/dist/skillpacks/geo/skills/geo-generating-actions/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-generating-actions/references/orchestrator.workflow.md +0 -440
- package/dist/skillpacks/geo/skills/geo-generating-actions/scripts/geo-scaffold.mjs +0 -358
- package/dist/skillpacks/geo/skills/geo-generating-actions/scripts/geo.mjs +0 -66
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/SKILL.md +0 -50
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/external-authority-diagnosis.md +0 -66
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/foundation-diagnosis.md +0 -86
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/memory-contract.md +0 -15
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/semantic-clusters-diagnosis.md +0 -58
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/strategy-map-contract.md +0 -26
- package/dist/skillpacks/geo/skills/geo-initializing-strategy/references/visibility-diagnosis.md +0 -50
- package/dist/skillpacks/geo/skills/geo-local-setup/SKILL.md +0 -66
- package/dist/skillpacks/geo/skills/geo-local-setup/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-page-writer/SKILL.md +0 -81
- package/dist/skillpacks/geo/skills/geo-page-writer/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-page-writer/references/research.md +0 -61
- package/dist/skillpacks/geo/skills/geo-page-writer/references/validation.md +0 -59
- package/dist/skillpacks/geo/skills/geo-page-writer/references/writing.md +0 -55
- package/dist/skillpacks/geo/skills/geo-page-writer/scripts/check-page-mdx.mjs +0 -210
- package/dist/skillpacks/geo/skills/geo-page-writer/scripts/collect-page-sources.mjs +0 -303
- package/dist/skillpacks/geo/skills/geo-pages-diagnosis/SKILL.md +0 -51
- package/dist/skillpacks/geo/skills/geo-pages-diagnosis/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-pages-diagnosis/references/diagnosis-contract.md +0 -125
- package/dist/skillpacks/geo/skills/geo-pages-diagnosis/references/workflow.md +0 -269
- package/dist/skillpacks/geo/skills/geo-writer/SKILL.md +0 -234
- package/dist/skillpacks/geo/skills/geo-writer/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/geo-writer/references/content-writer-contract.md +0 -316
- package/dist/skillpacks/geo/skills/geo-writer/references/direct-sql.md +0 -187
- package/dist/skillpacks/geo/skills/geo-writer/references/seo-geo-insights.md +0 -269
- package/dist/skillpacks/geo/skills/seo-ecommerce-opportunity/SKILL.md +0 -82
- package/dist/skillpacks/geo/skills/seo-ecommerce-opportunity/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-ecommerce-opportunity/references/ecommerce-rules.md +0 -31
- package/dist/skillpacks/geo/skills/seo-internal-link-opportunity/SKILL.md +0 -57
- package/dist/skillpacks/geo/skills/seo-internal-link-opportunity/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-internal-link-opportunity/references/link-rules.md +0 -28
- package/dist/skillpacks/geo/skills/seo-opportunity-audit/SKILL.md +0 -141
- package/dist/skillpacks/geo/skills/seo-opportunity-audit/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-opportunity-audit/references/action-contract.md +0 -62
- package/dist/skillpacks/geo/skills/seo-opportunity-audit/scripts/seo-toolkit.mjs +0 -248
- package/dist/skillpacks/geo/skills/seo-page-diagnosis/SKILL.md +0 -56
- package/dist/skillpacks/geo/skills/seo-page-diagnosis/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-page-diagnosis/references/page-checks.md +0 -38
- package/dist/skillpacks/geo/skills/seo-serp-opportunity-research/SKILL.md +0 -66
- package/dist/skillpacks/geo/skills/seo-serp-opportunity-research/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-serp-opportunity-research/references/page-type-taxonomy.md +0 -40
- package/dist/skillpacks/geo/skills/seo-serp-opportunity-research/references/serp-methodology.md +0 -38
- package/dist/skillpacks/geo/skills/seo-technical-diagnosis/SKILL.md +0 -64
- package/dist/skillpacks/geo/skills/seo-technical-diagnosis/agents/openai.yaml +0 -5
- package/dist/skillpacks/geo/skills/seo-technical-diagnosis/references/checks.md +0 -58
- package/dist/skillpacks/geo/skills/third-party-diagnosis/SKILL.md +0 -54
- package/dist/skillpacks/geo/skills/third-party-diagnosis/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/third-party-diagnosis/references/diagnosis-contract.md +0 -111
- package/dist/skillpacks/geo/skills/third-party-diagnosis/references/workflow.md +0 -174
- package/dist/skillpacks/geo/skills/third-party-execution-planning/SKILL.md +0 -64
- package/dist/skillpacks/geo/skills/third-party-execution-planning/agents/openai.yaml +0 -4
- package/dist/skillpacks/geo/skills/third-party-execution-planning/references/execution-contract.md +0 -90
- package/dist/skillpacks/geo/skills/third-party-execution-planning/references/non-social-surface-playbooks.md +0 -123
- package/dist/skillpacks/geo/skills/third-party-execution-planning/references/reddit-rules.md +0 -69
- package/dist/skillpacks/geo/skills/third-party-execution-planning/references/social-platform-playbooks.md +0 -59
package/README.md
CHANGED
|
@@ -145,9 +145,9 @@ anymorph init
|
|
|
145
145
|
anymorph init --skills-source /path/to/anymorph-geo-skills/skills
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
By default, `init`
|
|
149
|
-
`anymorph`
|
|
150
|
-
|
|
148
|
+
By default, `init` downloads the GEO skillpack from the authenticated Anymorph
|
|
149
|
+
API. Run `anymorph login` first. The public npm package does not bundle
|
|
150
|
+
proprietary GEO skillpacks. `--skills-source` is only for internal local
|
|
151
151
|
development when testing an unreleased skillpack.
|
|
152
152
|
|
|
153
153
|
This installs managed skills under `.claude/skills` and `.agents/skills`,
|
package/dist/index.js
CHANGED
|
@@ -12254,6 +12254,7 @@ var require_src = __commonJS({
|
|
|
12254
12254
|
generationMode: z.enum(["full", "lite"]).optional(),
|
|
12255
12255
|
tierMix: PromptGenTierMixSchema.optional(),
|
|
12256
12256
|
realizationMode: z.enum(["auto", "llm", "deterministic"]).optional(),
|
|
12257
|
+
brandProfile: z.record(z.string(), z.unknown()).optional(),
|
|
12257
12258
|
additionalContext: z.string().trim().min(1).max(2e4).optional(),
|
|
12258
12259
|
userRequest: z.string().trim().min(1).max(2e4).optional(),
|
|
12259
12260
|
async: z.boolean().optional(),
|
|
@@ -15892,6 +15893,7 @@ async function gitOutput(repoPath, args) {
|
|
|
15892
15893
|
|
|
15893
15894
|
// src/geo/scaffold.ts
|
|
15894
15895
|
import { execFile as execFile7 } from "node:child_process";
|
|
15896
|
+
import { createHash } from "node:crypto";
|
|
15895
15897
|
import {
|
|
15896
15898
|
cp,
|
|
15897
15899
|
mkdir as mkdir3,
|
|
@@ -15901,7 +15903,7 @@ import {
|
|
|
15901
15903
|
stat as stat2,
|
|
15902
15904
|
writeFile as writeFile2
|
|
15903
15905
|
} from "node:fs/promises";
|
|
15904
|
-
import {
|
|
15906
|
+
import { homedir as homedir2 } from "node:os";
|
|
15905
15907
|
import { dirname, join as join4, relative, resolve as resolve2 } from "node:path";
|
|
15906
15908
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15907
15909
|
import { promisify as promisify7 } from "node:util";
|
|
@@ -15919,6 +15921,12 @@ var MANAGED_PATHS = [
|
|
|
15919
15921
|
"agent/contracts"
|
|
15920
15922
|
];
|
|
15921
15923
|
var BUNDLED_SKILLPACK_RELATIVE_PATH = join4("skillpacks", "geo", "skills");
|
|
15924
|
+
var AUTHENTICATED_SKILLPACK_CACHE_DIR = join4(
|
|
15925
|
+
homedir2(),
|
|
15926
|
+
".anymorph",
|
|
15927
|
+
"skillpacks",
|
|
15928
|
+
"geo"
|
|
15929
|
+
);
|
|
15922
15930
|
async function initGeoScaffold(input) {
|
|
15923
15931
|
return applyGeoScaffold(input, { createMemory: true });
|
|
15924
15932
|
}
|
|
@@ -15976,12 +15984,14 @@ async function resolveSkillSourceDir(explicit) {
|
|
|
15976
15984
|
}
|
|
15977
15985
|
const bundled = await resolveBundledSkillSourceDir();
|
|
15978
15986
|
if (bundled) return bundled;
|
|
15987
|
+
const authenticated = await downloadAuthenticatedSkillpack();
|
|
15988
|
+
if (authenticated) return authenticated;
|
|
15979
15989
|
for (const root of searchRoots()) {
|
|
15980
15990
|
const candidate = join4(root, DEFAULT_SKILLPACK_RELATIVE_PATH);
|
|
15981
15991
|
if (await isDirectory(candidate)) return candidate;
|
|
15982
15992
|
}
|
|
15983
15993
|
throw new Error(
|
|
15984
|
-
`Could not find
|
|
15994
|
+
`Could not find a GEO skillpack. Run \`anymorph login\` to download it, or pass --skills-source <path> pointing to ${DEFAULT_SKILLPACK_RELATIVE_PATH}.`
|
|
15985
15995
|
);
|
|
15986
15996
|
}
|
|
15987
15997
|
async function resolveBundledSkillSourceDir(fromUrl = new URL(import.meta.url)) {
|
|
@@ -16196,6 +16206,69 @@ async function readCliPackageVersion() {
|
|
|
16196
16206
|
}
|
|
16197
16207
|
return null;
|
|
16198
16208
|
}
|
|
16209
|
+
async function downloadAuthenticatedSkillpack() {
|
|
16210
|
+
let response;
|
|
16211
|
+
try {
|
|
16212
|
+
response = await apiRequest("GET", "/api/cli/geo-skillpack");
|
|
16213
|
+
} catch (err) {
|
|
16214
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16215
|
+
throw new Error(`Could not download GEO skillpack: ${message}`);
|
|
16216
|
+
}
|
|
16217
|
+
if (!response.ok) {
|
|
16218
|
+
const detail = await response.text().catch(() => "");
|
|
16219
|
+
throw new Error(
|
|
16220
|
+
`Could not download GEO skillpack: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
16221
|
+
);
|
|
16222
|
+
}
|
|
16223
|
+
const payload = parseAuthenticatedSkillpackResponse(await response.json());
|
|
16224
|
+
const cacheDir = join4(
|
|
16225
|
+
AUTHENTICATED_SKILLPACK_CACHE_DIR,
|
|
16226
|
+
payload.manifestHash.replace(/^sha256:/, "")
|
|
16227
|
+
);
|
|
16228
|
+
await rm(cacheDir, { recursive: true, force: true });
|
|
16229
|
+
await mkdir3(cacheDir, { recursive: true });
|
|
16230
|
+
for (const file of payload.files) {
|
|
16231
|
+
const target = safeJoin(cacheDir, file.path);
|
|
16232
|
+
await mkdir3(dirname(target), { recursive: true });
|
|
16233
|
+
await writeFile2(target, file.content);
|
|
16234
|
+
}
|
|
16235
|
+
return join4(cacheDir, "skills");
|
|
16236
|
+
}
|
|
16237
|
+
function parseAuthenticatedSkillpackResponse(value) {
|
|
16238
|
+
if (!value || typeof value !== "object") {
|
|
16239
|
+
throw new Error("Invalid GEO skillpack response");
|
|
16240
|
+
}
|
|
16241
|
+
const record = value;
|
|
16242
|
+
const files = record.files;
|
|
16243
|
+
if (record.name !== "anymorph-geo" || typeof record.ref !== "string" || typeof record.manifestHash !== "string" || !record.manifestHash.startsWith("sha256:") || !Array.isArray(files)) {
|
|
16244
|
+
throw new Error("Invalid GEO skillpack response");
|
|
16245
|
+
}
|
|
16246
|
+
return {
|
|
16247
|
+
name: record.name,
|
|
16248
|
+
ref: record.ref,
|
|
16249
|
+
manifestHash: record.manifestHash,
|
|
16250
|
+
files: files.map((file) => {
|
|
16251
|
+
if (!file || typeof file !== "object") {
|
|
16252
|
+
throw new Error("Invalid GEO skillpack file entry");
|
|
16253
|
+
}
|
|
16254
|
+
const entry = file;
|
|
16255
|
+
if (typeof entry.path !== "string" || typeof entry.content !== "string") {
|
|
16256
|
+
throw new Error("Invalid GEO skillpack file entry");
|
|
16257
|
+
}
|
|
16258
|
+
return { path: entry.path, content: entry.content };
|
|
16259
|
+
})
|
|
16260
|
+
};
|
|
16261
|
+
}
|
|
16262
|
+
function safeJoin(root, path2) {
|
|
16263
|
+
if (path2.startsWith("/") || path2.includes("\\") || path2.split("/").includes("..")) {
|
|
16264
|
+
throw new Error(`Invalid GEO skillpack file path: ${path2}`);
|
|
16265
|
+
}
|
|
16266
|
+
const target = resolve2(root, path2);
|
|
16267
|
+
if (!target.startsWith(`${resolve2(root)}/`)) {
|
|
16268
|
+
throw new Error(`Invalid GEO skillpack file path: ${path2}`);
|
|
16269
|
+
}
|
|
16270
|
+
return target;
|
|
16271
|
+
}
|
|
16199
16272
|
function searchRoots() {
|
|
16200
16273
|
const roots = /* @__PURE__ */ new Set();
|
|
16201
16274
|
let cwd = resolve2(process.cwd());
|
|
@@ -16622,7 +16695,7 @@ function shortPath(path2) {
|
|
|
16622
16695
|
function buildWorkflowCommands() {
|
|
16623
16696
|
const commands = [];
|
|
16624
16697
|
commands.push(
|
|
16625
|
-
new Command("init").description("Initialize GEO scaffold and skills in a tenant repo").option("--skills-source <path>", "Use an explicit GEO skillpack source directory
|
|
16698
|
+
new Command("init").description("Initialize GEO scaffold and skills in a tenant repo").option("--skills-source <path>", "Use an explicit local GEO skillpack source directory").option("--ref <ref>", "Skillpack ref label to write into agent/skillpack.json", "authenticated").option("--json", "Output as JSON").addHelpText(
|
|
16626
16699
|
"after",
|
|
16627
16700
|
`
|
|
16628
16701
|
Examples:
|
|
@@ -16634,7 +16707,7 @@ agent/runs, agent/archive, and missing tenant memory files.`
|
|
|
16634
16707
|
).action(geoInitCommand)
|
|
16635
16708
|
);
|
|
16636
16709
|
commands.push(
|
|
16637
|
-
new Command("doctor").description("Check whether a tenant repo GEO scaffold matches the installed skillpack").option("--skills-source <path>", "Use an explicit GEO skillpack source directory
|
|
16710
|
+
new Command("doctor").description("Check whether a tenant repo GEO scaffold matches the installed skillpack").option("--skills-source <path>", "Use an explicit local GEO skillpack source directory").option("--fix", "Repair managed GEO scaffold files without touching memory or run artifacts").option("--ref <ref>", "Skillpack ref label to write into agent/skillpack.json when using --fix", "authenticated").option("--json", "Output as JSON").addHelpText(
|
|
16638
16711
|
"after",
|
|
16639
16712
|
`
|
|
16640
16713
|
Examples:
|
|
@@ -16647,7 +16720,7 @@ managed files without deleting run artifacts or tenant memory.`
|
|
|
16647
16720
|
).action(geoDoctorCommand)
|
|
16648
16721
|
);
|
|
16649
16722
|
commands.push(
|
|
16650
|
-
new Command("prepare").argument("<workspaceId>").description("Prepare a local GEO strategy run package").option("--days <days>", "Signal lookback window in days", parsePositiveInt).option("--skills-source <path>", "Use an explicit GEO skillpack source directory
|
|
16723
|
+
new Command("prepare").argument("<workspaceId>").description("Prepare a local GEO strategy run package").option("--days <days>", "Signal lookback window in days", parsePositiveInt).option("--skills-source <path>", "Use an explicit local GEO skillpack source directory").option("--skip-scaffold", "Skip GEO scaffold sync before writing the run package").option("--json", "Output as JSON").addHelpText(
|
|
16651
16724
|
"after",
|
|
16652
16725
|
`
|
|
16653
16726
|
Examples:
|
|
@@ -17076,7 +17149,7 @@ function printScaffoldError(prefix, err) {
|
|
|
17076
17149
|
|
|
17077
17150
|
// src/index.ts
|
|
17078
17151
|
var program2 = new Command();
|
|
17079
|
-
program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.
|
|
17152
|
+
program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.6.0");
|
|
17080
17153
|
program2.command("login").description("Sign in to your Anymorph account").addHelpText(
|
|
17081
17154
|
"after",
|
|
17082
17155
|
`
|
package/package.json
CHANGED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Anymorph GEO Tenant Repo
|
|
2
|
-
|
|
3
|
-
This tenant repo uses Anymorph's local GEO workflow.
|
|
4
|
-
|
|
5
|
-
Codex reads this file. Claude reads `CLAUDE.md`. Both runtimes use the same
|
|
6
|
-
managed skillpack installed under `.agents/skills` and `.claude/skills`, plus
|
|
7
|
-
shared references under `.agents/shared` and `.claude/shared`.
|
|
8
|
-
|
|
9
|
-
Run Anymorph CLI commands from the repository root.
|
|
10
|
-
|
|
11
|
-
At the first user request in a new agent session, check whether the installed
|
|
12
|
-
`anymorph` CLI can be updated before running GEO workflow commands. Update it
|
|
13
|
-
when npm has a newer published version, then run `anymorph doctor` to confirm
|
|
14
|
-
the managed skillpack is fresh.
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
CURRENT=$(anymorph --version 2>/dev/null || true)
|
|
18
|
-
LATEST=$(npm view anymorph version 2>/dev/null || true)
|
|
19
|
-
if [ -n "$LATEST" ] && [ "$CURRENT" != "$LATEST" ]; then
|
|
20
|
-
npm install -g anymorph@latest
|
|
21
|
-
fi
|
|
22
|
-
anymorph doctor
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
anymorph init
|
|
27
|
-
anymorph doctor
|
|
28
|
-
anymorph prepare <workspaceId>
|
|
29
|
-
anymorph validate <runId>
|
|
30
|
-
anymorph submit <runId>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Rules
|
|
34
|
-
|
|
35
|
-
- Do not edit managed files under `.agents/skills`, `.agents/shared`, `.claude/skills`, `.claude/shared`, or `agent/contracts` by hand.
|
|
36
|
-
- Keep stable brand and strategy context in `agent/BRAND.md`, `agent/STRATEGY.md`, and `agent/LEARNINGS.md`.
|
|
37
|
-
- Write run artifacts only under `agent/runs/{runId}` unless a skill explicitly says otherwise.
|
|
38
|
-
- Run `anymorph doctor` when managed skill behavior looks stale.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Anymorph GEO Tenant Repo
|
|
2
|
-
|
|
3
|
-
This repository is a tenant workspace for Anymorph GEO work.
|
|
4
|
-
|
|
5
|
-
Claude reads this file. Codex reads `AGENTS.md`. Both runtimes use the same
|
|
6
|
-
managed skillpack installed under `.claude/skills` and `.agents/skills`, plus
|
|
7
|
-
shared references under `.claude/shared` and `.agents/shared`.
|
|
8
|
-
|
|
9
|
-
At the first user request in a new Claude Code session, check whether the
|
|
10
|
-
installed `anymorph` CLI can be updated before running GEO workflow commands.
|
|
11
|
-
Update it when npm has a newer published version, then run `anymorph doctor` to
|
|
12
|
-
confirm the managed skillpack is fresh.
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
CURRENT=$(anymorph --version 2>/dev/null || true)
|
|
16
|
-
LATEST=$(npm view anymorph version 2>/dev/null || true)
|
|
17
|
-
if [ -n "$LATEST" ] && [ "$CURRENT" != "$LATEST" ]; then
|
|
18
|
-
npm install -g anymorph@latest
|
|
19
|
-
fi
|
|
20
|
-
anymorph doctor
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Use the root `AGENTS.md` for shared agent rules. Claude-specific local behavior should still follow the Anymorph CLI workflow:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
anymorph init
|
|
27
|
-
anymorph doctor
|
|
28
|
-
anymorph prepare <workspaceId>
|
|
29
|
-
anymorph validate <runId>
|
|
30
|
-
anymorph submit <runId>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Do not manually patch managed skill copies or shared references under `.claude/` or `.agents/`; repair them with `anymorph doctor --fix`.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Evidence Principles
|
|
2
|
-
|
|
3
|
-
Use this shared reference for claim, evidence, freshness, and structured-data judgment across GEO skills.
|
|
4
|
-
|
|
5
|
-
## Claim Strength
|
|
6
|
-
|
|
7
|
-
- Do not create claims stronger than the approved evidence source.
|
|
8
|
-
- Distinguish product facts, positioning, customer evidence, third-party evidence, and agent inference.
|
|
9
|
-
- If evidence is absent, stale, ambiguous, jurisdiction-specific, or compliance-sensitive, flag for review instead of publishing or recommending the claim.
|
|
10
|
-
- Do not summarize reviews, UGC, case studies, or external commentary into a stronger claim than the source supports.
|
|
11
|
-
|
|
12
|
-
## Source Hierarchy
|
|
13
|
-
|
|
14
|
-
- Prefer first-party approved records for brand, product, price, availability, policy, certification, and compliance facts.
|
|
15
|
-
- Use product catalog, approved documentation, trust centers, policy pages, feeds, and brand-managed KB before external research.
|
|
16
|
-
- Use external research to understand market context, comparison criteria, definitions, and third-party authority. Do not use it to invent brand-specific facts.
|
|
17
|
-
- For comparison claims, record the criteria, date, source, and scope.
|
|
18
|
-
|
|
19
|
-
## Freshness
|
|
20
|
-
|
|
21
|
-
- Facts involving price, availability, policy, certification, integration support, hours, inventory, fees, shipping, returns, regulatory status, or live booking state need source, date, and refresh cadence.
|
|
22
|
-
- Label live, feed-supplied, estimated, seasonal, and stale facts clearly.
|
|
23
|
-
- Prefer no claim over a stale or unsupported claim.
|
|
24
|
-
|
|
25
|
-
## Structured Data
|
|
26
|
-
|
|
27
|
-
- Structured data must match visible page content.
|
|
28
|
-
- Valid structured data can improve eligibility for supported search experiences, but does not guarantee display, ranking, or AI citation.
|
|
29
|
-
- Do not add schema for hidden, misleading, fake, outdated, or unsupported content.
|
|
30
|
-
|
|
31
|
-
## GEO/AEO Framing
|
|
32
|
-
|
|
33
|
-
- Do not treat GEO/AEO as separate from technical SEO, content quality, entity clarity, structured data accuracy, and evidence governance.
|
|
34
|
-
- Pages should be useful, crawlable, self-contained, source-aware, and explicit about assumptions.
|
|
35
|
-
- AI search inclusion, citation, and recommendation are not guaranteed outcomes.
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
# GEO Principles — Anymorph MCP
|
|
2
|
-
|
|
3
|
-
이 문서는 Anymorph GEO Skills의 모든 sub-Skill이 공유하는 원칙이다.
|
|
4
|
-
sub-Skill 본문에 인라인으로 복붙하지 말고, 필요한 항목만 한 줄 링크로 참조할 것.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 1. Generative Engine Optimization(GEO) 정의
|
|
9
|
-
|
|
10
|
-
### GEO vs 전통 SEO
|
|
11
|
-
|
|
12
|
-
전통 SEO는 Google 검색 결과 페이지(SERP)의 순위를 올리는 작업이다.
|
|
13
|
-
KPI는 "클릭률(CTR)", "페이지 1 진입", "organic traffic" 등 SERP 기반 지표다.
|
|
14
|
-
|
|
15
|
-
GEO는 다르다. 목표는 **AI 엔진(ChatGPT, Gemini, Perplexity, Claude 등)이 사용자 질문에
|
|
16
|
-
답변할 때 우리 브랜드 페이지를 인용 소스로 채택하게 만드는 것**이다.
|
|
17
|
-
KPI는 "AI 응답 내 인용 빈도(citation rate)", "intent 커버리지", "AI 가시성 점수"다.
|
|
18
|
-
|
|
19
|
-
### 왜 다른가
|
|
20
|
-
|
|
21
|
-
- LLM은 SERP 순위를 보지 않는다. 크롤된 콘텐츠를 학습 or RAG로 직접 참조한다.
|
|
22
|
-
- AI가 인용하는 조건: 사실 밀도, 구조 명확성, 신뢰 신호, 도메인 권위.
|
|
23
|
-
- 트래픽 경로가 바뀐다: "검색 → 클릭 → 사이트" 대신 "AI 답변 → 브랜드 노출 → 직접 유입".
|
|
24
|
-
- GEO 최적화 페이지는 SEO에도 도움이 되지만, 역은 성립하지 않는다.
|
|
25
|
-
|
|
26
|
-
### Anymorph MCP의 역할
|
|
27
|
-
|
|
28
|
-
Anymorph MCP는 26개 도구로 GEO Visibility Loop를 자동화한다:
|
|
29
|
-
- 현재 AI 가시성 측정 → 약한 intent 탐지 → 경쟁사 gap 분석 → 키워드 리서치
|
|
30
|
-
- brand voice kit 추출 → managed remote 생성/수정 또는 tenant repo 직접 수정 → 발행 후 재검증
|
|
31
|
-
|
|
32
|
-
MCP 도구 하나하나를 수동으로 호출하는 대신, sub-Skill이 올바른 순서와 인자로 도구를 자동 조합한다.
|
|
33
|
-
페이지 생성·수정은 작업 목적에 따라 실행 경로를 고른다. Dashboard 상태, DB, preview/build, version 관리와 일치해야 하면 Anymorph MCP managed workflow를 사용한다. 사용자가 로컬 tenant repo 경로를 제공했거나 코드/컴포넌트/레이아웃을 직접 고쳐야 하면 Claude Code가 tenant repo를 직접 수정할 수 있다. 이 둘은 대체 관계가 아니라 서로 다른 실행 경로다.
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## 2. AI 인용 패턴 (Citation Patterns)
|
|
38
|
-
|
|
39
|
-
AI 엔진이 어떤 페이지를 인용 소스로 선택하는지는 공개된 연구와 역분석으로 파악된다.
|
|
40
|
-
아래는 Anymorph가 확인한 핵심 패턴이다.
|
|
41
|
-
|
|
42
|
-
### 2-1. 명확한 사실 진술
|
|
43
|
-
|
|
44
|
-
- 검증 가능한 수치/날짜/이름이 있는 문장이 우선 인용된다.
|
|
45
|
-
- 좋음: "2024년 기준 국내 전기차 판매량은 17만 2천 대(한국자동차산업협회)."
|
|
46
|
-
- 나쁨: "최근 전기차 시장이 크게 성장했습니다."
|
|
47
|
-
- 수치는 출처 명시와 함께 써야 인용 신뢰도가 올라간다.
|
|
48
|
-
|
|
49
|
-
### 2-2. 구조화된 헤딩
|
|
50
|
-
|
|
51
|
-
- H1 한 개 (페이지 intent를 한 문장으로 요약).
|
|
52
|
-
- H2/H3 계층이 명확해야 LLM이 섹션 단위로 chunking한다.
|
|
53
|
-
- 헤딩만 읽어도 페이지 전체 흐름이 파악되어야 한다.
|
|
54
|
-
|
|
55
|
-
### 2-3. 자기완결적 단락
|
|
56
|
-
|
|
57
|
-
- 한 단락 = 한 아이디어. LLM은 토큰 단위로 단락을 추출한다.
|
|
58
|
-
- 전 단락을 읽지 않아도 이해되는 단락이 인용되기 쉽다.
|
|
59
|
-
- 단락 길이는 3-6 문장 권장. 너무 길면 chunking 경계에서 의미가 잘린다.
|
|
60
|
-
|
|
61
|
-
### 2-4. 출처 명시
|
|
62
|
-
|
|
63
|
-
- 인용·통계·연구에 링크 또는 "(출처: …)" 표기.
|
|
64
|
-
- 외부 권위 있는 출처(학술지, 정부 기관, 업계 표준 기관)를 인용하면
|
|
65
|
-
AI 엔진이 페이지를 신뢰 노드로 분류할 가능성이 높아진다.
|
|
66
|
-
|
|
67
|
-
### 2-5. schema.org 구조화 데이터
|
|
68
|
-
|
|
69
|
-
- FAQ → `FAQPage` schema: AI가 Q&A를 직접 추출해 답변에 포함.
|
|
70
|
-
- HowTo → `HowToStep` schema: 단계별 가이드 인용 최적화.
|
|
71
|
-
- Article → `datePublished`, `dateModified`, `author` 필드 필수.
|
|
72
|
-
- 구조화 데이터는 Anymorph 페이지 생성 시 자동 삽입되지만,
|
|
73
|
-
`get_page` 도구로 확인 후 누락된 필드가 있으면 명시적으로 요청할 것.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## 3. 신뢰 신호 (Trust Signals)
|
|
78
|
-
|
|
79
|
-
AI 인용 후보가 되려면 단순히 정보가 많은 것만으로는 부족하다.
|
|
80
|
-
신뢰 신호가 쌓여야 한다.
|
|
81
|
-
|
|
82
|
-
### 3-1. 브랜드 voice/tone 일관성
|
|
83
|
-
|
|
84
|
-
- `get_brand_voice_kit` 도구로 추출한 tone(formal/conversational 등),
|
|
85
|
-
vocabulary, 금지 표현을 페이지 전체에 일관 적용.
|
|
86
|
-
- AI는 일관성 없는 tone을 "복수 저자 or 저품질 콘텐츠"로 분류한다.
|
|
87
|
-
|
|
88
|
-
### 3-2. Brand-curated 사실 우선
|
|
89
|
-
|
|
90
|
-
- `search_living_document` 도구로 workspace의 brand-curated 사실 베이스를 조회.
|
|
91
|
-
- 외부 출처를 쓰기 전에 living document에 동일 사실이 있는지 먼저 확인.
|
|
92
|
-
- living document에 없는 사실을 추가하려면 사용자(브랜드 담당자)에게 확인 요청.
|
|
93
|
-
|
|
94
|
-
### 3-3. 편향 없는 인용
|
|
95
|
-
|
|
96
|
-
- 경쟁사·외부 출처도 팩트 근거로 인용하면 AI 엔진이 더 신뢰한다.
|
|
97
|
-
- "우리 브랜드만 좋다"는 편향된 서술은 AI가 광고성 콘텐츠로 분류해 인용을 기피.
|
|
98
|
-
- 균형 잡힌 비교 섹션(장단점, 시장 전반 현황)을 포함할 것.
|
|
99
|
-
|
|
100
|
-
### 3-4. 발행 후 갱신 이력
|
|
101
|
-
|
|
102
|
-
- `dateModified` 필드와 "마지막 업데이트: YYYY-MM-DD" 가시적 표기 필수.
|
|
103
|
-
- AI는 갱신된 콘텐츠를 stale 콘텐츠보다 우선 인용한다.
|
|
104
|
-
- `refreshing-existing-pages` Skill은 이 갱신 이력을 자동 관리한다.
|
|
105
|
-
|
|
106
|
-
### 3-5. 도메인 depth
|
|
107
|
-
|
|
108
|
-
- 같은 브랜드 도메인 내에 관련 페이지가 많을수록 도메인 권위가 높아진다.
|
|
109
|
-
- 단발성 랜딩 페이지 하나보다 "keyword cluster" 전략(관련 키워드 10-20페이지 군집)이 효과적.
|
|
110
|
-
- `creating-keyword-landing-pages` Skill은 cluster 단위 생성을 지원한다.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 4. Authoring Execution Model
|
|
115
|
-
|
|
116
|
-
Anymorph GEO Skill은 인증 모델을 사용자에게 설명하는 문서가 아니다. 핵심은 어떤 실행 경로를 선택할지다.
|
|
117
|
-
|
|
118
|
-
| 경로 | 사용 시점 | 대표 도구/동작 |
|
|
119
|
-
|------|-----------|----------------|
|
|
120
|
-
| Managed remote generation | 새 페이지를 Dashboard/backend 상태와 맞춰 생성해야 할 때 | `generate_managed_pages` → `get_managed_operation` |
|
|
121
|
-
| Managed remote edit | 기존 페이지를 원격 sandbox에서 수정하고 version/build handoff까지 남겨야 할 때 | `edit_managed_page` → 사용자 확인 → `confirm_managed_page_edit` |
|
|
122
|
-
| Tenant repo direct edit | 사용자가 tenant repo 경로를 제공했거나 코드/레이아웃 직접 수정이 목적일 때 | 로컬 파일 수정 → repo build/test/review |
|
|
123
|
-
| Research-only draft | 사용자가 먼저 방향, brief, 초안을 검토하려 할 때 | 리서치 요약과 authoring brief 출력 |
|
|
124
|
-
|
|
125
|
-
도구 호출이 인증 문제로 실패하면 내부 인증 항목을 나열하지 말고, 실패한 단계와 다음 선택지만 짧게 말한다: 재인증 후 같은 경로 재시도, 가능한 다른 경로로 전환, 또는 research-only draft로 마무리.
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## 5. Visibility Loop 5단계
|
|
130
|
-
|
|
131
|
-
GEO 작업은 항상 이 루프를 따른다. 각 단계의 산출물이 다음 단계의 입력이다.
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
Audit → Diagnose → Research → Author → Verify
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 5-1. Audit (현재 가시성 측정)
|
|
138
|
-
|
|
139
|
-
**도구**: `get_page_visibility`, `list_weak_intents`
|
|
140
|
-
|
|
141
|
-
- `list_weak_intents(workspaceId)` → intent score가 임계값 미만인 페이지 목록.
|
|
142
|
-
- `get_page_visibility(pageId)` → 특정 페이지의 intent별 visibility score.
|
|
143
|
-
- **산출물**: 보강이 필요한 intent 목록 + 현재 점수 분포.
|
|
144
|
-
|
|
145
|
-
**트리거 Skill**: `recovering-weak-intents`, `verifying-published-pages`
|
|
146
|
-
|
|
147
|
-
### 5-2. Diagnose (약한 지점 진단)
|
|
148
|
-
|
|
149
|
-
**도구**: `get_competitor_gap`, `get_page_insights`
|
|
150
|
-
|
|
151
|
-
- `get_competitor_gap(pageId)` → 경쟁사 대비 우리 페이지가 다루지 못한 주제.
|
|
152
|
-
- `get_page_insights(pageId)` → 페이지 구조·사실 밀도·신뢰 신호 점수.
|
|
153
|
-
- **산출물**: 보강 대상 섹션 목록, 경쟁사가 커버하는 키워드 gap.
|
|
154
|
-
|
|
155
|
-
### 5-3. Research (보강 자료 수집)
|
|
156
|
-
|
|
157
|
-
**도구**: `search_keywords`, `serp_snapshot`, `search_living_document`
|
|
158
|
-
|
|
159
|
-
- `search_keywords(query, locationCode, languageCode)` → 관련 키워드 + 검색량/난이도.
|
|
160
|
-
- `serp_snapshot(keyword)` → 현재 SERP 상위 결과 구조 파악.
|
|
161
|
-
- `search_living_document(workspaceId, query)` → brand-curated 사실 베이스 조회.
|
|
162
|
-
- **산출물**: 사용할 키워드 목록, 인용할 사실 목록, 경쟁 페이지 구조 패턴.
|
|
163
|
-
|
|
164
|
-
**주의**: `search_keywords`가 인증/사용량 문제로 실패하면 키워드 리서치를 건너뛰고 사용자 제공 키워드로 진행한다.
|
|
165
|
-
|
|
166
|
-
### 5-4. Author (페이지 생성/갱신)
|
|
167
|
-
|
|
168
|
-
**도구**: `get_brand_voice_kit`, `get_workspace_instructions`, `generate_managed_pages`, `edit_managed_page`, `confirm_managed_page_edit`, `get_managed_operation`
|
|
169
|
-
|
|
170
|
-
- `get_brand_voice_kit(workspaceId)` → tone, vocabulary, 금지 표현.
|
|
171
|
-
- `get_workspace_instructions(workspaceId)` → 페이지 생성 시 추가 지침.
|
|
172
|
-
- 새 페이지는 Research 단계 산출물을 `title`, `description`, `context`로 합성해 `generate_managed_pages`를 호출한다.
|
|
173
|
-
- JSON-LD는 raw tool input으로 전달하지 않는다. `context`에 structured data intent만 적고, 실제 schema.org 출력은 생성 파이프라인이 페이지 타입/상품/FAQ 데이터로 만들게 둔다.
|
|
174
|
-
- 기존 페이지는 진단 결과를 edit prompt로 합성해 `edit_managed_page`를 호출하고, 사용자 승인 후 `confirm_managed_page_edit`를 호출한다.
|
|
175
|
-
- tenant repo 직접 수정 경로에서는 MCP write tool 대신 로컬 파일을 수정하고 repo의 build/test/review 절차를 따른다.
|
|
176
|
-
- 상태는 별도 MCP-only operation record가 아니라 `get_managed_operation`으로 기존 batch/session/page 상태를 읽는다.
|
|
177
|
-
- **산출물**: 선택한 경로에 따라 Dashboard와 같은 DB 상태/preview/version이 남는 managed operation, 또는 tenant repo의 코드 변경.
|
|
178
|
-
|
|
179
|
-
**트리거 Skill**: `creating-keyword-landing-pages`, `refreshing-existing-pages`
|
|
180
|
-
|
|
181
|
-
### 5-5. Verify (발행 후 검증)
|
|
182
|
-
|
|
183
|
-
**도구**: `get_page_visibility`, `get_page_insights`
|
|
184
|
-
|
|
185
|
-
- 발행 후 24-72시간 대기 (AI 엔진 크롤 주기).
|
|
186
|
-
- `get_page_visibility(pageId)` 재호출 → 점수 변화 확인.
|
|
187
|
-
- 점수가 개선되지 않으면 Diagnose 단계로 되돌아가 원인 분석.
|
|
188
|
-
- **산출물**: Before/After 가시성 점수 비교 리포트.
|
|
189
|
-
|
|
190
|
-
**트리거 Skill**: `verifying-published-pages`
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## 6. 공통 실패 모드 (Common Failure Modes)
|
|
195
|
-
|
|
196
|
-
sub-Skill 작성 시 반드시 처리해야 하는 에러 케이스 목록.
|
|
197
|
-
|
|
198
|
-
### 6-1. workspaceId 미일치
|
|
199
|
-
|
|
200
|
-
**에러**: `WorkspaceClaimMismatchError`
|
|
201
|
-
|
|
202
|
-
- JWT의 `workspaceIds` 배열에 포함된 ID만 사용 가능.
|
|
203
|
-
- `list_workspaces()` 도구로 접근 가능한 workspace 목록을 먼저 조회.
|
|
204
|
-
- 사용자가 다른 workspace ID를 요청하면 목록을 보여주고 재선택 유도.
|
|
205
|
-
|
|
206
|
-
```
|
|
207
|
-
❌ WorkspaceClaimMismatchError: workspace 'ws_xxxx' is not in your token.
|
|
208
|
-
→ 접근 가능한 workspace: list_workspaces() 결과를 보여줄게요.
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### 6-2. 도구 인증 또는 접근 실패
|
|
212
|
-
|
|
213
|
-
- 실패한 도구와 영향받는 workflow 단계만 짧게 설명한다.
|
|
214
|
-
- 가능한 우회 경로가 있으면 바로 제안한다.
|
|
215
|
-
- 재인증이 필요한 경우에도 내부 인증 항목을 길게 나열하지 않는다.
|
|
216
|
-
|
|
217
|
-
```
|
|
218
|
-
search_keywords 호출이 인증 문제로 실패했습니다.
|
|
219
|
-
→ 키워드 리서치를 건너뛰고 사용자 제공 키워드로 계속 진행할 수 있습니다.
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 6-3. DataForSEO 결과 0건 (비영어 시장)
|
|
223
|
-
|
|
224
|
-
**증상**: `search_keywords` 결과가 빈 배열.
|
|
225
|
-
|
|
226
|
-
- `(locationCode, languageCode)` pair가 맞지 않으면 결과 0건.
|
|
227
|
-
- 기본값: Brand의 `primaryLocationCode` + `primaryLang` 자동 사용.
|
|
228
|
-
- 비기본 시장(예: ko-KR이 아닌 en-US로 한국 쿼리) → `targetOverride` 인자 명시.
|
|
229
|
-
- `get_brand_profile(workspaceId)` 로 `primaryLocationCode`, `primaryLang` 확인 후 정렬.
|
|
230
|
-
|
|
231
|
-
```python
|
|
232
|
-
# 예시: ko-KR 명시
|
|
233
|
-
search_keywords(query="비건 화장품 추천", locationCode=2410, languageCode="ko")
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### 6-4. Brand voice kit이 null
|
|
237
|
-
|
|
238
|
-
**증상**: `get_brand_voice_kit` 반환값이 `null` or 빈 객체.
|
|
239
|
-
|
|
240
|
-
- workspace에 Brand row가 없거나 voice kit이 미설정됨.
|
|
241
|
-
- Fallback: `get_brand_profile(workspaceId)`로 브랜드 기본 정보(이름, 업종) 추출.
|
|
242
|
-
- 사용자에게 Anymorph Dashboard에서 Brand 설정을 완료해 달라고 안내.
|
|
243
|
-
- voice kit 없이 작성할 경우 "중립적 professional tone"으로 폴백하고 명시.
|
|
244
|
-
|
|
245
|
-
```
|
|
246
|
-
⚠️ brand voice kit을 찾을 수 없습니다.
|
|
247
|
-
→ Anymorph Dashboard > Brand 설정에서 voice kit을 등록해주세요.
|
|
248
|
-
→ 지금은 중립적 professional tone으로 초안을 작성합니다.
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 6-5. 키워드 언어와 brand primaryLang 불일치
|
|
252
|
-
|
|
253
|
-
**증상**: 키워드는 영어인데 brand primaryLang은 ko-KR.
|
|
254
|
-
|
|
255
|
-
- `get_brand_voice_kit(workspaceId)`에서 `primaryLang`, `supportedLangs` 먼저 확인.
|
|
256
|
-
- 사용자가 영어 키워드를 요청했는데 brand가 한국어 전용이면:
|
|
257
|
-
1. `supportedLangs`에 en-US가 포함되어 있는지 확인.
|
|
258
|
-
2. 포함: 해당 language로 page 생성 진행.
|
|
259
|
-
3. 미포함: 사용자에게 언어 범위 확인 요청.
|
|
260
|
-
- 페이지 언어와 SERP 타겟 언어가 다르면 AI 인용 신뢰도 하락.
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
⚠️ 요청 키워드 언어(en)가 brand primaryLang(ko)과 다릅니다.
|
|
264
|
-
→ supportedLangs: [ko, en] — en-US 타겟으로 진행하겠습니다.
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### 6-6. 페이지 미존재 (refreshing 시나리오)
|
|
268
|
-
|
|
269
|
-
**증상**: `get_page(pageId)` → 404 or `PageNotFoundError`.
|
|
270
|
-
|
|
271
|
-
- pageId 오타 or 삭제된 페이지.
|
|
272
|
-
- `list_managed_pages(workspaceId, query/path/status)` 로 유사 경로와 같은 `clusterKey` 후보 제안.
|
|
273
|
-
- 없으면 `creating-keyword-landing-pages` Skill로 신규 생성 전환 안내.
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
## Author Note
|
|
278
|
-
|
|
279
|
-
> **Author note**: 이 원칙은 sub-Skill에서 본문에 인라인으로 인용하지 마세요.
|
|
280
|
-
> 필요한 항목만 한 줄 링크로 참조하세요.
|
|
281
|
-
> 예: `자세한 인용 패턴은 [shared/geo-principles.md §2](../shared/geo-principles.md#2-ai-인용-패턴-citation-patterns) 참조`
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# Beauty SEO/GEO/AEO Playbook
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
Reusable guidance for beauty, skincare, makeup, haircare, and personal care. Use this for vertical strategy, diagnosis, and page planning. Keep tenant-specific bets in `agent/STRATEGY.md`.
|
|
6
|
-
|
|
7
|
-
## Entity And Demand Patterns
|
|
8
|
-
|
|
9
|
-
- Beauty demand is combinatorial: `ingredient x concern`, `product type x skin type`, `routine step x concern`, `finish/effect x use case`, and `authenticity/where-to-buy x product`.
|
|
10
|
-
- Core entities: product type, ingredient, skin or hair concern, skin or hair type, routine step, finish, retailer, claim, evidence, review.
|
|
11
|
-
- Common modifiers include oily, dry, sensitive-feeling, acne-prone, mature, darker skin tones, fragrance-free, travel-size, and refillable. Pregnancy/lactation and disease-adjacent modifiers require review before use.
|
|
12
|
-
- Users need discovery and reassurance: fit, safety, authenticity, real-user experience, expected results, and where to buy.
|
|
13
|
-
- Cluster by reusable intent, not exact keyword wording. One strong canonical asset should cover related phrasings when the user need is the same.
|
|
14
|
-
|
|
15
|
-
## Search And AI Surfaces
|
|
16
|
-
|
|
17
|
-
- Standard organic results for education and shopping research.
|
|
18
|
-
- Concern-led pages may appear in AI search experiences only when they are crawlable, indexed, snippet-eligible, helpful, and policy-compliant. Inclusion is not guaranteed.
|
|
19
|
-
- Product snippets and merchant listings for buyable PDPs.
|
|
20
|
-
- Google Images, Lens, shopping modules, retailer PDPs, and marketplace search.
|
|
21
|
-
- Review, editorial, and comparison surfaces for `best for`, concern, and product-alternative intent.
|
|
22
|
-
- Brand-owned pages should be the official source for education, product facts, authenticity, and usage guidance.
|
|
23
|
-
- Retailer surfaces often win on availability, shipping, returns, and review volume. Treat them as part of the journey.
|
|
24
|
-
|
|
25
|
-
## Asset Plays
|
|
26
|
-
|
|
27
|
-
- Concern hubs: explain the concern, safe language boundaries, ingredient/product fit, routine options, and when to seek professional advice.
|
|
28
|
-
- Ingredient hubs: define the ingredient, common pairings, limits, product matches, formulation nuance, and evidence level.
|
|
29
|
-
- Product type x skin type pages: help users narrow choices with texture, finish, compatibility, and routine role.
|
|
30
|
-
- Routine guides: morning/night order, what to combine, what to avoid, product bundles, and user context.
|
|
31
|
-
- PDP upgrades: complete product identity, ingredients, usage, texture, imagery, reviews, price, availability, and structured data.
|
|
32
|
-
- Authenticity / where-to-buy pages: official retailer list, counterfeit avoidance, seller trust, shipping, returns, and FAQ.
|
|
33
|
-
- Comparison pages: compare ingredients, products, or routines with explicit criteria, pros/cons, and user-fit guidance.
|
|
34
|
-
- Review and UGC summaries: summarize representative themes without amplifying unsubstantiated therapeutic, safety, or atypical-result claims.
|
|
35
|
-
|
|
36
|
-
## Evidence And Claim Safety
|
|
37
|
-
|
|
38
|
-
- Cosmetic claims must be truthful, not misleading, and supported by visible evidence.
|
|
39
|
-
- Disease treatment, prevention, structure/function, SPF, hair-loss, acne, eczema, rosacea, psoriasis, melasma, and wrinkle claims need extra review.
|
|
40
|
-
- Pregnancy, lactation, children-related, SPF, acne, dandruff, hair growth/loss, eczema, rosacea, psoriasis, and melasma claims require explicit brand-approved evidence and regulatory review.
|
|
41
|
-
- Agents must not infer pregnancy safety, disease suitability, or therapeutic effect from ingredient lists.
|
|
42
|
-
- Ingredient guidance should distinguish ingredient presence from concentration, formulation, pH, delivery system, contact time, and product-level testing.
|
|
43
|
-
- Do not let visible copy, FAQ, UGC quotes, structured data, influencer scripts, and merchant data drift apart.
|
|
44
|
-
- Do not imply atypical before/after outcomes are normal unless the evidence supports that framing.
|
|
45
|
-
- Avoid fake reviews, review gating, undisclosed incentives, and pay-to-play comparison placements.
|
|
46
|
-
- Prefer suitability, routine role, texture, finish, ingredient role, and user context over therapeutic promises.
|
|
47
|
-
- Price, availability, shipping, returns, and authorized retailer facts are freshness-sensitive.
|
|
48
|
-
|
|
49
|
-
## Measurement Signals
|
|
50
|
-
|
|
51
|
-
- Non-brand ingredient, concern, product type, and routine impressions.
|
|
52
|
-
- PDP conversion, retailer outbound CTR, add-to-cart, checkout starts, and where-to-buy interactions.
|
|
53
|
-
- Product snippet and merchant listing eligibility, errors, and warnings.
|
|
54
|
-
- Review coverage, review freshness, UGC disclosure coverage, and claim QA pass rate.
|
|
55
|
-
- AI mention share, owned citation share, answer accuracy, and surfaced competitor/reviewer sources.
|
|
56
|
-
- Availability accuracy and consistency across brand site, schema, merchant data, and retailers.
|
|
57
|
-
|
|
58
|
-
## Anti-Patterns
|
|
59
|
-
|
|
60
|
-
- Thin programmatic pages for every ingredient/concern pair without distinct evidence.
|
|
61
|
-
- Unsupported cosmetic-to-drug claims in headings, FAQs, UGC pull-quotes, or schema.
|
|
62
|
-
- Product pages that hide price, availability, shipping, returns, or seller trust.
|
|
63
|
-
- Text-light pages where key facts only exist in images or video.
|
|
64
|
-
- `best for` pages without comparison logic, user context, pros/cons, or proof.
|
|
65
|
-
- Inconsistent product facts across owned site, merchant data, and retailer listings.
|