@ainyc/canonry 4.30.0 → 4.31.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 +15 -13
- package/assets/agent-workspace/skills/aero/SKILL.md +2 -2
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +26 -17
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +9 -9
- package/assets/agent-workspace/skills/aero/references/orchestration.md +6 -6
- package/assets/agent-workspace/skills/aero/references/reporting.md +3 -3
- package/assets/agent-workspace/skills/canonry/SKILL.md +5 -3
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +9 -9
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +203 -200
- package/assets/agent-workspace/skills/canonry/references/indexing.md +35 -35
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +18 -18
- package/assets/agent-workspace/skills/canonry/references/wordpress-integration.md +11 -11
- package/assets/assets/index-C4UBTDDS.js +302 -0
- package/assets/assets/{index-BnALDZI7.css → index-CNKAwZMB.css} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-NIAAHWRF.js → chunk-5STLZRGB.js} +5 -3
- package/dist/{chunk-7UO3EGDB.js → chunk-HTNC6AWN.js} +24 -2
- package/dist/{chunk-PTFVEYUX.js → chunk-PUTJHEVR.js} +130 -13
- package/dist/{chunk-4EDC2P3J.js → chunk-U3YKRV47.js} +1 -1
- package/dist/cli.js +55 -14
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-ASXADXLF.js → intelligence-service-CJONZ7ST.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +8 -7
- package/assets/assets/index-BYiZYtd9.js +0 -302
package/README.md
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
- Watch AI engines crawl and refer traffic via [server-log ingestion](skills/canonry/references/server-side-traffic.md) — Cloud Run logs and the WordPress Traffic Logger plugin today
|
|
9
9
|
- Diagnose against real traffic with built-in [GSC](docs/google-search-console-setup.md), [GA4](docs/google-analytics-setup.md), and [Bing Webmaster](docs/bing-webmaster-setup.md)
|
|
10
10
|
- Execute fixes via [WordPress](docs/wordpress-setup.md), JSON-LD schema, and indexing submissions
|
|
11
|
-
- Manage many clients declaratively — config-as-code YAML + `
|
|
11
|
+
- Manage many clients declaratively — config-as-code YAML + `cnry apply`
|
|
12
12
|
- Schedule recurring visibility checks AND traffic syncs, with webhook alerts on regressions
|
|
13
|
-
- Generate client-ready HTML reports — `
|
|
13
|
+
- Generate client-ready HTML reports — `cnry report <project>`
|
|
14
14
|
- Drive from your own agent via the [67-tool MCP adapter](docs/mcp.md) or webhooks
|
|
15
15
|
- Or use **Aero** — Canonry's built-in agent that wakes up after every run
|
|
16
16
|
|
|
@@ -22,28 +22,30 @@ Every dashboard view has a matching CLI command and API endpoint. The CLI is the
|
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
npm install -g @ainyc/canonry
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
cnry init
|
|
26
|
+
cnry serve
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
The CLI installs as `cnry` (short form) and `canonry` — the two are interchangeable.
|
|
30
|
+
|
|
29
31
|
Open [http://localhost:4100/setup](http://localhost:4100/setup). A guided wizard walks you through provider keys, project setup, queries, and your first visibility check.
|
|
30
32
|
|
|
31
33
|
Prefer the terminal?
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
cnry project create my-site --domain example.com
|
|
37
|
+
cnry query add my-site "your first query" "second query"
|
|
38
|
+
cnry run my-site --wait
|
|
39
|
+
cnry evidence my-site
|
|
40
|
+
cnry insights my-site
|
|
39
41
|
```
|
|
40
42
|
|
|
41
43
|
## If you get stuck
|
|
42
44
|
|
|
43
45
|
| Problem | Fix |
|
|
44
46
|
|---------|-----|
|
|
45
|
-
| No provider key configured | Grab a free [Gemini key](https://aistudio.google.com/apikey), set `GEMINI_API_KEY`, restart `
|
|
46
|
-
| No results after a run | Visibility checks are async — check the Runs tab or use `
|
|
47
|
+
| No provider key configured | Grab a free [Gemini key](https://aistudio.google.com/apikey), set `GEMINI_API_KEY`, restart `cnry serve`. |
|
|
48
|
+
| No results after a run | Visibility checks are async — check the Runs tab or use `cnry run <project> --wait`. |
|
|
47
49
|
| Not sure what queries to test | The setup wizard auto-generates them by analyzing your site. |
|
|
48
50
|
| `npm install` fails on `node-gyp` | Install build tools for `better-sqlite3` ([guide](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/troubleshooting.md)). |
|
|
49
51
|
|
|
@@ -57,7 +59,7 @@ canonry insights my-site
|
|
|
57
59
|
| Perplexity | [perplexity.ai/settings/api](https://www.perplexity.ai/settings/api) | `PERPLEXITY_API_KEY` |
|
|
58
60
|
| Local LLMs | Any OpenAI-compatible endpoint | `LOCAL_LLM_URL` |
|
|
59
61
|
|
|
60
|
-
Configure during `
|
|
62
|
+
Configure during `cnry init`, in the dashboard `/settings`, or as env vars.
|
|
61
63
|
|
|
62
64
|
## Documentation
|
|
63
65
|
|
|
@@ -69,7 +71,7 @@ Configure during `canonry init`, in the dashboard `/settings`, or as env vars.
|
|
|
69
71
|
| **Integrations** | [GSC](docs/google-search-console-setup.md) · [GA4](docs/google-analytics-setup.md) · [Bing](docs/bing-webmaster-setup.md) · [WordPress](docs/wordpress-setup.md) · [Server-side traffic (Cloud Run + WordPress logs)](skills/canonry/references/server-side-traffic.md) |
|
|
70
72
|
| **Deployment** — Docker, Railway, Render, systemd, Tailscale | [docs/deployment.md](docs/deployment.md) |
|
|
71
73
|
| **API** — 118+ endpoints | `GET /api/v1/openapi.json` (no auth) |
|
|
72
|
-
| **Skills bundle** for Claude Code / Codex | `
|
|
74
|
+
| **Skills bundle** for Claude Code / Codex | `cnry skills install` ([details](skills/canonry/SKILL.md)) |
|
|
73
75
|
| **Roadmap & ADRs** | [docs/roadmap.md](docs/roadmap.md) · [docs/adr/](docs/adr/) |
|
|
74
76
|
| **All docs** | [docs/README.md](docs/README.md) |
|
|
75
77
|
|
|
@@ -9,12 +9,12 @@ repository: https://github.com/AINYC/aero
|
|
|
9
9
|
# Aero Orchestration Skill
|
|
10
10
|
|
|
11
11
|
You coordinate across two tools to deliver comprehensive AEO monitoring:
|
|
12
|
-
- **canonry** — the source of truth for project state (runs, snapshots, timelines, insights, audit log, **GA4 traffic + AI/social referrals**). Query it with `
|
|
12
|
+
- **canonry** — the source of truth for project state (runs, snapshots, timelines, insights, audit log, **GA4 traffic + AI/social referrals**). Query it with `cnry <command> --format json` (the CLI is also installed as `canonry` — the two are interchangeable); never maintain a parallel copy in agent memory.
|
|
13
13
|
- **aeo-audit** — on-demand site analysis and fix generation.
|
|
14
14
|
|
|
15
15
|
Persist only *user-scoped* context (operator preferences, communication style) in your platform's native memory. Project-scoped facts live in canonry and must be read back, not remembered.
|
|
16
16
|
|
|
17
|
-
When a project has GA4 connected, traffic is a first-class signal alongside citations. Use `
|
|
17
|
+
When a project has GA4 connected, traffic is a first-class signal alongside citations. Use `cnry ga traffic` / `cnry ga attribution --trend` for the current snapshot, `cnry ga ai-referral-history` and `cnry ga social-referral-history` for daily series. Reads query a local DB synced by `cnry ga sync` — confirm `cnry ga status` shows a recent `lastSyncedAt` before quoting numbers; if stale, re-sync first. Full command reference and return shapes live in the co-installed `canonry/references/canonry-cli.md` (look for the "Google Analytics 4" section).
|
|
18
18
|
|
|
19
19
|
## Judgment Rules
|
|
20
20
|
|
|
@@ -11,7 +11,15 @@ Discovery turns a free-text ICP description into a deduped basket of representat
|
|
|
11
11
|
- **wasted-surface** — a tracked competitor is cited but the project is not
|
|
12
12
|
- **aspirational** — neither the project nor a tracked competitor is cited (greenfield)
|
|
13
13
|
|
|
14
|
-
Plus a competitor map: every non-canonical domain that shows up in probe citations, ranked by hit count, so the operator can spot recurring competitors that aren't yet on the watchlist.
|
|
14
|
+
Plus a competitor map: every non-canonical domain that shows up in probe citations, ranked by hit count and classified by type, so the operator can spot recurring competitors that aren't yet on the watchlist.
|
|
15
|
+
|
|
16
|
+
After probing, one Gemini call classifies every recurring cited domain into a `competitorType`:
|
|
17
|
+
|
|
18
|
+
- **direct-competitor** — a business competing for the same customers (another hotel, another tool in the category). The only type promoted by default.
|
|
19
|
+
- **ota-aggregator** — OTAs, marketplaces, directories, review aggregators (expedia.com, booking.com, g2.com). Suppressed from competitor tracking.
|
|
20
|
+
- **editorial-media** — news, blogs, "best of" round-ups (timeout.com, a personal blog). A *channel* to earn placement in, not a competitor — suppressed by default.
|
|
21
|
+
- **other** — government sites, social platforms, off-topic domains. Suppressed.
|
|
22
|
+
- **unknown** — classification failed, or a session that pre-dates classification. Excluded from the default promote.
|
|
15
23
|
|
|
16
24
|
## When discovery is the right move
|
|
17
25
|
|
|
@@ -24,7 +32,7 @@ Plus a competitor map: every non-canonical domain that shows up in probe citatio
|
|
|
24
32
|
The operator runs:
|
|
25
33
|
|
|
26
34
|
```bash
|
|
27
|
-
|
|
35
|
+
cnry discover run <project> --icp "..." --wait
|
|
28
36
|
```
|
|
29
37
|
|
|
30
38
|
Or the MCP equivalent: `canonry_discover_run_start` with `{ project, request: { icpDescription, dedupThreshold?, maxProbes? } }`. The endpoint returns `{ runId, sessionId, status: "running" }` immediately and finishes the work in the background. Poll `canonry_discover_session_get` until `status` is `completed` or `failed`.
|
|
@@ -39,13 +47,13 @@ Per session: ~$1 at the default probe budget (100 queries × 1 Gemini grounded c
|
|
|
39
47
|
|
|
40
48
|
`canonry_discover_session_get` returns:
|
|
41
49
|
|
|
42
|
-
- Session-level: `seedCountRaw` vs `seedCount` (proves embedding dedup did real work), bucket counts, `competitorMap` (top recurring non-tracked domains).
|
|
50
|
+
- Session-level: `seedCountRaw` vs `seedCount` (proves embedding dedup did real work), bucket counts, `competitorMap` (top recurring non-tracked domains, each with `hits` and `competitorType`).
|
|
43
51
|
- Per-probe: query, bucket, citation state, the cited domains list.
|
|
44
52
|
|
|
45
53
|
Things to call out without being asked:
|
|
46
54
|
|
|
47
55
|
- **High wasted-surface ratio** (≥ 40% of probes, or > cited count at ≥ 20%) → the project is missing from its own competitive space. The auto-written `discovery.basket-divergence` insight flags this as `high` severity.
|
|
48
|
-
- **Recurring
|
|
56
|
+
- **Recurring `direct-competitor` domains** in `competitorMap` that aren't already in the project's tracked competitor list → `cnry discover promote` adopts `direct-competitor` domains with at least 2 hits automatically alongside the queries; or add them à la carte with `cnry competitor add <project> <domain>`. Domains classified `ota-aggregator` / `editorial-media` / `other` are surfaced but **not** promoted by default — flag a recurring `editorial-media` site as a placement opportunity, not a competitor.
|
|
49
57
|
- **Aspirational greenfield** queries with no tracked competitor and no canonical cite → low-friction content opportunities.
|
|
50
58
|
|
|
51
59
|
## Promoting a session into the tracked basket
|
|
@@ -53,7 +61,7 @@ Things to call out without being asked:
|
|
|
53
61
|
Once a session is `completed`, preview first unless the operator has already approved the write:
|
|
54
62
|
|
|
55
63
|
```bash
|
|
56
|
-
|
|
64
|
+
cnry discover promote preview <project> <session-id>
|
|
57
65
|
```
|
|
58
66
|
|
|
59
67
|
Or the MCP equivalent: `canonry_discover_promote_preview` with `{ project, sessionId }`.
|
|
@@ -63,15 +71,16 @@ The preview returns every bucket so you can explain the tradeoff:
|
|
|
63
71
|
- `cited` — already grounded to the project, safe to track.
|
|
64
72
|
- `aspirational` — greenfield ICP-fit opportunities, safe to track as a growth basket.
|
|
65
73
|
- `wasted-surface` — competitor-cited but project-missing. Treat as content-planning evidence first; do not add it to the weekly tracked basket unless the operator explicitly wants those off-ICP competitor gaps tracked.
|
|
66
|
-
- `suggestedCompetitors` — recurring domains not already tracked
|
|
74
|
+
- `suggestedCompetitors` — recurring domains (≥ 2 hits) not already tracked, of **every** classified type, each tagged with `competitorType`. The default promote adopts only the `direct-competitor` ones; the others are shown so you can recommend a `--competitor-types` widening.
|
|
67
75
|
|
|
68
76
|
Promote with one of these paths:
|
|
69
77
|
|
|
70
78
|
```bash
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
cnry discover promote <project> <session-id> # cited + aspirational buckets + direct-competitor domains
|
|
80
|
+
cnry discover promote <project> <session-id> --bucket aspirational # scope to a bucket subset (repeatable / comma-separated)
|
|
81
|
+
cnry discover promote <project> <session-id> --bucket wasted-surface # explicitly track off-ICP competitor gaps
|
|
82
|
+
cnry discover promote <project> <session-id> --competitor-types direct-competitor,editorial-media # widen the competitor merge to other classified types
|
|
83
|
+
cnry discover promote <project> <session-id> --no-competitors # queries only, skip the competitor merge
|
|
75
84
|
```
|
|
76
85
|
|
|
77
86
|
Or the MCP equivalent:
|
|
@@ -80,14 +89,14 @@ Or the MCP equivalent:
|
|
|
80
89
|
{ "project": "<project>", "sessionId": "<session-id>" }
|
|
81
90
|
```
|
|
82
91
|
|
|
83
|
-
That default request promotes `cited` + `aspirational` queries and
|
|
92
|
+
That default request promotes `cited` + `aspirational` queries and `direct-competitor` domains. For scoped writes, pass `request`:
|
|
84
93
|
|
|
85
94
|
```json
|
|
86
|
-
{ "project": "<project>", "sessionId": "<session-id>", "request": { "buckets": ["aspirational"], "includeCompetitors": false } }
|
|
95
|
+
{ "project": "<project>", "sessionId": "<session-id>", "request": { "buckets": ["aspirational"], "competitorTypes": ["direct-competitor", "editorial-media"], "includeCompetitors": false } }
|
|
87
96
|
```
|
|
88
97
|
|
|
89
98
|
- **Default is cited + aspirational.** `wasted-surface` queries are off-ICP competitor gaps; promote them only when the operator explicitly wants those tracked in the weekly basket.
|
|
90
|
-
- **Competitor promotion requires recurrence.**
|
|
99
|
+
- **Competitor promotion requires recurrence + a promotable type.** The default competitor merge ignores one-off domains (< 2 hits) and adopts only domains classified `direct-competitor`. Pass `competitorTypes` (CLI: `--competitor-types`) to also adopt `editorial-media` channels, or `competitorTypes: ["unknown"]` to recover a legacy session promoted before classification existed.
|
|
91
100
|
- **Add-only and idempotent.** Queries and competitor domains already tracked are returned under `skipped`, never inserted twice. Re-running a promote is safe.
|
|
92
101
|
- **Completed sessions only.** Promoting a `queued`/`seeding`/`probing`/`failed` session is rejected — the buckets aren't final.
|
|
93
102
|
- Promoted rows carry `provenance="discovery:<sessionId>"`, so a tracked query can always be traced back to the session that surfaced it.
|
|
@@ -106,8 +115,8 @@ Respond with:
|
|
|
106
115
|
|
|
107
116
|
1. A one-line headline naming the dominant bucket.
|
|
108
117
|
2. The top 2-3 wasted-surface queries (call `canonry_discover_session_get` to fetch them — don't guess).
|
|
109
|
-
3. The top 1-2 recurring
|
|
110
|
-
4. A single recommended next step. Examples: "preview and promote cited + aspirational findings (`
|
|
118
|
+
3. The top 1-2 recurring `direct-competitor` domains worth tracking, ignoring one-hit domains unless the operator asks for the full long tail. If a recurring `editorial-media` domain stands out, mention it separately as a placement opportunity — not a competitor.
|
|
119
|
+
4. A single recommended next step. Examples: "preview and promote cited + aspirational findings (`cnry discover promote preview`, then `cnry discover promote`)", "the wasted-surface set warrants a content plan around X before tracking", "the aspirational set is greenfield — pick the 3 with highest commercial intent and write content".
|
|
111
120
|
|
|
112
121
|
Do not recommend "promote everything" as the default. The safe path is: inspect session detail, preview promotion candidates, then promote the default cited + aspirational set. Escalate `wasted-surface` to tracking only when the operator deliberately chooses that tradeoff.
|
|
113
122
|
|
|
@@ -120,7 +129,7 @@ Keep it tight. The operator wakes to a short, decision-ready summary, not a full
|
|
|
120
129
|
|
|
121
130
|
## Failure modes
|
|
122
131
|
|
|
123
|
-
- **Gemini not configured** → orchestrator throws early; `runs.status='failed'` with `Gemini provider is not configured.` Surface as "configure Gemini before running discovery" — link to `
|
|
132
|
+
- **Gemini not configured** → orchestrator throws early; `runs.status='failed'` with `Gemini provider is not configured.` Surface as "configure Gemini before running discovery" — link to `cnry init` or `~/.canonry/config.yaml`.
|
|
124
133
|
- **Vertex-only Gemini** → embeddings step throws (Vertex embeddings deferred). Same surface, "use a Gemini API key for now."
|
|
125
134
|
- **ICP missing** → route returns 400 with `VALIDATION_ERROR`. Ask the operator for the ICP description in plain language.
|
|
126
135
|
- **Seed collapse (hyperlocal/niche businesses)** → 40 raw seeds collapse to 1-2 canonical queries after embedding+clustering, even at low dedup thresholds. This happens when Gemini generates seed queries that all live in the same semantic pocket (e.g. all variants of "boutique hotel Venice Beach"). The embedding model sees them as near-identical, so clustering produces one representative.
|
|
@@ -130,7 +139,7 @@ Keep it tight. The operator wakes to a short, decision-ready summary, not a full
|
|
|
130
139
|
**Remediation:** break the ICP into 3-5 distinct purchase-intent angles and run one session per angle via `--icp-angle`:
|
|
131
140
|
|
|
132
141
|
```bash
|
|
133
|
-
|
|
142
|
+
cnry discover run <project> \
|
|
134
143
|
--icp-angle "romantic anniversary stay in Venice Beach" \
|
|
135
144
|
--icp-angle "best rooftop bars and dining hotels LA" \
|
|
136
145
|
--icp-angle "walkable Venice Beach hotels near Abbot Kinney" \
|
|
@@ -22,12 +22,12 @@ Aero ships with a built-in durable notes store — the `canonry_memory_set`, `ca
|
|
|
22
22
|
Prefer Aero's read tools (`canonry_project_overview`, `canonry_health_latest`, `canonry_timeline_get`, `canonry_insights_list`, `canonry_queries_list`, `canonry_competitors_list`, `canonry_run_get`) over shelling out, but the CLI exists for operators too:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
cnry status <project> --format json
|
|
26
|
+
cnry health <project> --format json
|
|
27
|
+
cnry timeline <project> --since <YYYY-MM-DD> --format json
|
|
28
|
+
cnry insights <project> --format json
|
|
29
|
+
cnry evidence <project> --format json
|
|
30
|
+
cnry audit <project> --format json
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
If the data you need isn't reachable with a single read tool or CLI call, that's a bug in canonry's API surface — file it rather than working around it in memory.
|
|
@@ -47,9 +47,9 @@ Derived interpretations (trend summaries, correlations between events) are cheap
|
|
|
47
47
|
**CLI parity.** Operators can manage memory without talking to you:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
cnry agent memory list <project> --format json
|
|
51
|
+
cnry agent memory set <project> --key <k> --value <v>
|
|
52
|
+
cnry agent memory forget <project> --key <k>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
## Good remember candidates
|
|
@@ -10,7 +10,7 @@ description: Workflow recipes — baseline, regression response, weekly review,
|
|
|
10
10
|
Trigger: First sweep completes for a new project
|
|
11
11
|
|
|
12
12
|
Steps:
|
|
13
|
-
1. `
|
|
13
|
+
1. `cnry evidence <project> --format json` → get initial citation data
|
|
14
14
|
2. Compute baseline: cited rate, provider breakdown, top/bottom queries
|
|
15
15
|
3. `npx @ainyc/aeo-audit "<domain>" --format json` → site readiness score
|
|
16
16
|
4. Identify top 3 gaps (uncited queries with fixable site issues)
|
|
@@ -22,9 +22,9 @@ Steps:
|
|
|
22
22
|
Trigger: Comparison shows decline or webhook fires regression.detected
|
|
23
23
|
|
|
24
24
|
Steps:
|
|
25
|
-
1. `
|
|
26
|
-
2. `
|
|
27
|
-
3. Check indexing: `
|
|
25
|
+
1. `cnry evidence <project> --format json` → current state
|
|
26
|
+
2. `cnry history <project>` → trend for affected query
|
|
27
|
+
3. Check indexing: `cnry google coverage <project>` → is the page still indexed?
|
|
28
28
|
4. Check competitor: did a competitor gain the citation we lost?
|
|
29
29
|
5. Audit the page: `npx @ainyc/aeo-audit "<page-url>" --format json`
|
|
30
30
|
6. Diagnose cause: indexing issue / content issue / competitive displacement
|
|
@@ -37,7 +37,7 @@ Steps:
|
|
|
37
37
|
Trigger: Scheduled (weekly, or on-demand)
|
|
38
38
|
|
|
39
39
|
Steps:
|
|
40
|
-
1. `
|
|
40
|
+
1. `cnry evidence <project> --format json` → current metrics
|
|
41
41
|
2. Compare to baseline/prior week from memory
|
|
42
42
|
3. Compute deltas: citations gained, lost, stable
|
|
43
43
|
4. Flag any new regressions not yet addressed
|
|
@@ -49,7 +49,7 @@ Steps:
|
|
|
49
49
|
Trigger: User asks "why aren't we cited for X?" or multiple uncited queries detected
|
|
50
50
|
|
|
51
51
|
Steps:
|
|
52
|
-
1. `
|
|
52
|
+
1. `cnry evidence <project>` → confirm uncited
|
|
53
53
|
2. Check if a relevant page exists on the domain
|
|
54
54
|
3. If no page: recommend content creation (topic, target queries)
|
|
55
55
|
4. If page exists: `npx @ainyc/aeo-audit "<page-url>"` → diagnose why uncited
|
|
@@ -10,9 +10,9 @@ description: Weekly and monthly report templates with metric tables, regression/
|
|
|
10
10
|
When a client asks for a "current state" or "AEO report" without a specific custom narrative, prefer the bundled report instead of hand-rolling sections:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
cnry report <project> # writes canonry-report-<project>-YYYY-MM-DD.html in cwd
|
|
14
|
+
cnry report <project> --output dist/aeo.html # custom path
|
|
15
|
+
cnry report <project> --format json # raw payload, useful for narrating in chat
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
The HTML is self-contained (inline CSS + SVG charts, no network dependencies) and covers: executive summary, per-query × per-provider citation matrix, competitor landscape, AI citation sources, GSC + GA4 performance, social and AI referrals, indexing health, citations trend, prioritized insights, and recommended next steps. Same payload is available via `GET /api/v1/projects/<name>/report` and the `canonry_report` MCP tool — use `--format json` when you want to summarize specific numbers in a thread instead of attaching the file.
|
|
@@ -36,6 +36,8 @@ Agent-first open-source AEO (Answer Engine Optimization) operating platform. Tra
|
|
|
36
36
|
|
|
37
37
|
**Website:** [ainyc.ai](https://ainyc.ai) | **Docs:** [github.com/AINYC/canonry](https://github.com/AINYC/canonry)
|
|
38
38
|
|
|
39
|
+
**CLI:** invoke as `cnry` (short form) or `canonry` — both ship with the npm package and are interchangeable. Examples in this skill use `cnry`.
|
|
40
|
+
|
|
39
41
|
## When to Use
|
|
40
42
|
|
|
41
43
|
- Tracking query citations across AI providers
|
|
@@ -56,11 +58,11 @@ Agent-first open-source AEO (Answer Engine Optimization) operating platform. Tra
|
|
|
56
58
|
|
|
57
59
|
A canonry engagement follows the same loop regardless of project size:
|
|
58
60
|
|
|
59
|
-
1. **Diagnose** — Run a baseline sweep (`
|
|
61
|
+
1. **Diagnose** — Run a baseline sweep (`cnry run <project> --wait`) and a technical audit (`npx @ainyc/aeo-audit@latest <url> --format json`). See `references/aeo-analysis.md` for interpretation.
|
|
60
62
|
2. **Prioritize** — Triage by impact: indexing gaps → schema gaps → content gaps → query strategy. Branded-term losses are urgent.
|
|
61
63
|
3. **Execute** — Apply fixes via the canonry CLI or platform integrations. See `references/canonry-cli.md` for the full command catalog and `references/wordpress-integration.md` for the WordPress workflow.
|
|
62
64
|
4. **Monitor** — Re-run sweeps weekly. Correlate visibility shifts with deployments and competitor moves.
|
|
63
|
-
5. **Report** — Lead with data, not interpretation: "Lost `<query>` on Gemini between <date> and <date> — two competitors moved in. Here's what to fix." For a one-command client-facing summary, run `
|
|
65
|
+
5. **Report** — Lead with data, not interpretation: "Lost `<query>` on Gemini between <date> and <date> — two competitors moved in. Here's what to fix." For a one-command client-facing summary, run `cnry report <project>` to generate a self-contained HTML bundle (executive summary, citation scorecard, competitor landscape, GSC + GA4 performance, insights). Same payload is available via `--format json` and the `canonry_report` MCP tool.
|
|
64
66
|
|
|
65
67
|
## Common Starting Points
|
|
66
68
|
|
|
@@ -70,7 +72,7 @@ A canonry engagement follows the same loop regardless of project size:
|
|
|
70
72
|
|
|
71
73
|
## Google Analytics 4
|
|
72
74
|
|
|
73
|
-
GA4 is a first-class signal alongside citation tracking. Connect once with `
|
|
75
|
+
GA4 is a first-class signal alongside citation tracking. Connect once with `cnry ga connect <project> --property-id <id> --key-file <path>`; `cnry ga sync` then pulls daily landing-page traffic, AI-referral sessions across 10 known providers (chatgpt, perplexity, claude, gemini, openai, anthropic, copilot, phind, you.com, meta.ai), and social referrals split into Organic vs Paid via GA4's `channelGroup` — and persists everything into four DB tables (`gaTrafficSnapshots`, `gaAiReferrals`, `gaSocialReferrals`, `gaTrafficSummaries`). All read commands query that local store, so they are fast and quotaless once a sync has run. AI referrals are tracked across three GA4 attribution dimensions (session source / first-user source / manual UTM) and joined to landing pages, so you can see which page each AI provider sent traffic to. Use `cnry ga traffic` for the current snapshot, `cnry ga attribution --trend` for a unified channel-share overview with biggest-mover deltas, and `cnry ga ai-referral-history` / `cnry ga social-referral-history` for daily series. See `references/canonry-cli.md` for the full command catalog and return-shape details.
|
|
74
76
|
|
|
75
77
|
## Boundaries & Safety
|
|
76
78
|
|
|
@@ -57,7 +57,7 @@ Shows which source categories AI models cite for your queries. Helps identify:
|
|
|
57
57
|
### Step 1: Check indexing first
|
|
58
58
|
Not cited ≠ bad content. Often the page isn't indexed yet.
|
|
59
59
|
```bash
|
|
60
|
-
|
|
60
|
+
cnry google coverage <project>
|
|
61
61
|
```
|
|
62
62
|
If key pages are "unknown to Google," submit them before drawing conclusions.
|
|
63
63
|
|
|
@@ -70,28 +70,28 @@ For competitive queries, if others are cited and the client isn't:
|
|
|
70
70
|
- Do they have stronger schema/structured data?
|
|
71
71
|
- Are they more established in the index?
|
|
72
72
|
|
|
73
|
-
Run `
|
|
73
|
+
Run `cnry evidence <project> --format json` and check `competitorOverlap` in snapshots.
|
|
74
74
|
|
|
75
75
|
### Step 4: Check across providers
|
|
76
76
|
Gemini, OpenAI, Claude, and Perplexity may behave differently. One citing a domain while another doesn't is normal — each has its own knowledge base and update schedule.
|
|
77
77
|
|
|
78
78
|
### Step 5: Check analytics trends
|
|
79
79
|
```bash
|
|
80
|
-
|
|
80
|
+
cnry analytics <project> --feature gaps --window 30d
|
|
81
81
|
```
|
|
82
82
|
Look for patterns: are gaps growing or shrinking? Are new competitors appearing?
|
|
83
83
|
|
|
84
84
|
### Step 6: Check GA4 traffic for impact
|
|
85
85
|
A lost citation isn't always a lost user. Before declaring a regression real, confirm whether AI-referral traffic actually fell on the same window:
|
|
86
86
|
```bash
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
cnry ga status <project> # confirm lastSyncedAt is recent; re-sync if stale
|
|
88
|
+
cnry ga ai-referral-history <project> --format json
|
|
89
89
|
# daily {date, source, medium, attribution, sessions, users}
|
|
90
|
-
|
|
90
|
+
cnry ga attribution <project> --trend # 7d/30d direction per channel + biggest mover
|
|
91
91
|
```
|
|
92
92
|
Read the result against the citation loss window:
|
|
93
93
|
- **AI sessions flat or up** → the citation loss may be sweep-side noise (provider variance, query refresh). Track for one more cycle before alarming the client.
|
|
94
|
-
- **AI sessions dropped on the same date** → real outage; escalate. Cross-reference `aiReferrals[]` from `
|
|
94
|
+
- **AI sessions dropped on the same date** → real outage; escalate. Cross-reference `aiReferrals[]` from `cnry ga traffic` to identify which provider lost traffic.
|
|
95
95
|
- **Organic dropped but AI held** → the citation loss is masking a separate indexing issue. Re-run Step 1.
|
|
96
96
|
|
|
97
97
|
GA4 also covers the inverse case: a *gain* on `attribution --trend` for the AI channel that isn't reflected in citation count usually means a provider expanded an existing citation's exposure (more queries triggering it) — a quiet win worth flagging in the next report.
|
|
@@ -106,14 +106,14 @@ GA4 also covers the inverse case: a *gain* on `attribution --trend` for the AI c
|
|
|
106
106
|
- Did a competitor page launch?
|
|
107
107
|
- Did the page get deindexed or go down?
|
|
108
108
|
- Did the model update?
|
|
109
|
-
- Check `
|
|
109
|
+
- Check `cnry google deindexed <project>` for index losses
|
|
110
110
|
|
|
111
111
|
**Fluctuation** (cited in some runs, not others) — normal for competitive queries. Track trend over 5+ runs before drawing conclusions. AI answers are non-deterministic.
|
|
112
112
|
|
|
113
113
|
## What to Recommend
|
|
114
114
|
|
|
115
115
|
### Low overall citation (< 50%)
|
|
116
|
-
1. Audit indexing — `
|
|
116
|
+
1. Audit indexing — `cnry google coverage <project>`
|
|
117
117
|
2. Submit unindexed pages to Google Indexing API
|
|
118
118
|
3. Submit sitemap to Bing WMT + send IndexNow batch
|
|
119
119
|
4. Check core pages for schema (LocalBusiness / Organization / FAQPage)
|