@canonry/canonry 4.104.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/LICENSE +105 -0
- package/README.md +117 -0
- package/assets/agent-workspace/AGENTS.md +88 -0
- package/assets/agent-workspace/USER.md +23 -0
- package/assets/agent-workspace/skills/aero/SKILL.md +72 -0
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +161 -0
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +66 -0
- package/assets/agent-workspace/skills/aero/references/orchestration.md +67 -0
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +58 -0
- package/assets/agent-workspace/skills/aero/references/reporting.md +98 -0
- package/assets/agent-workspace/skills/aero/references/wordpress-elementor-mcp.md +223 -0
- package/assets/agent-workspace/skills/aero/soul.md +30 -0
- package/assets/agent-workspace/skills/canonry/SKILL.md +152 -0
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +200 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +714 -0
- package/assets/agent-workspace/skills/canonry/references/google-business-profile.md +300 -0
- package/assets/agent-workspace/skills/canonry/references/indexing.md +163 -0
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +372 -0
- package/assets/agent-workspace/skills/canonry/references/wordpress-integration.md +61 -0
- package/assets/apple-touch-icon.png +0 -0
- package/assets/assets/BacklinksPage-CixBvw--.js +1 -0
- package/assets/assets/ChartPrimitives-CjX4mQCy.js +1 -0
- package/assets/assets/ProjectPage-C09hcd6v.js +7 -0
- package/assets/assets/RunRow-Bel7mWgu.js +1 -0
- package/assets/assets/RunsPage-wqKWA2Ei.js +1 -0
- package/assets/assets/SettingsPage-esOqUkW5.js +1 -0
- package/assets/assets/TrafficPage-V0iCV3l4.js +1 -0
- package/assets/assets/TrafficSourceDetailPage-DUeuOh2v.js +1 -0
- package/assets/assets/arrow-left-CVZPxpW6.js +1 -0
- package/assets/assets/extract-error-message-BWAlA7ea.js +1 -0
- package/assets/assets/index-LsyRFLMG.css +1 -0
- package/assets/assets/index-avJiga1P.js +210 -0
- package/assets/assets/trash-2-CA_L6uGC.js +1 -0
- package/assets/assets/vendor-markdown-6dwjPOKK.js +14 -0
- package/assets/assets/vendor-radix-CQ77EO2y.js +45 -0
- package/assets/assets/vendor-recharts-C9EZkgbP.js +36 -0
- package/assets/assets/vendor-tanstack-Be8JdV5M.js +1 -0
- package/assets/favicon-32.png +0 -0
- package/assets/favicon.svg +24 -0
- package/assets/index.html +25 -0
- package/bin/canonry-mcp.mjs +2 -0
- package/bin/canonry.mjs +2 -0
- package/dist/chunk-23DCY7DL.js +7030 -0
- package/dist/chunk-GIKNEXFE.js +12414 -0
- package/dist/chunk-GNMZTR6Y.js +35673 -0
- package/dist/chunk-Q7FFDQU4.js +5743 -0
- package/dist/cli.js +13344 -0
- package/dist/index.d.ts +260 -0
- package/dist/index.js +12 -0
- package/dist/intelligence-service-GM3RXE2F.js +7 -0
- package/dist/mcp.js +442 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Arber X
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Canonry <img src="https://raw.githubusercontent.com/Canonry/canonry/main/apps/web/public/favicon-32.png" alt="Canonry canary icon" width="24" />
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@canonry/canonry) [](https://nodejs.org)
|
|
4
|
+
|
|
5
|
+
**Agent-first AEO operating platform. Open source. Self-hosted.**
|
|
6
|
+
|
|
7
|
+
- Track citations across Gemini, ChatGPT, Claude, Perplexity, and local LLMs
|
|
8
|
+
- Watch AI engines crawl and refer traffic via [server-log ingestion](skills/canonry/references/server-side-traffic.md) — Cloud Run, Vercel, and the WordPress Traffic Logger plugin today
|
|
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
|
+
- Track local AEO via [Google Business Profile](skills/canonry/references/google-business-profile.md) — search-term impressions, performance metrics, and hotel lodging + booking-CTA gaps
|
|
11
|
+
- Discover who links to you with [Common Crawl backlinks](skills/canonry/references/canonry-cli.md#backlinks-common-crawl) — follows Common Crawl's rolling monthly hyperlink graph, auto-syncing each new window on a schedule, queried locally with DuckDB
|
|
12
|
+
- Execute fixes via [WordPress](docs/wordpress-setup.md), JSON-LD schema, and indexing submissions
|
|
13
|
+
- Manage many clients declaratively — config-as-code YAML + `cnry apply`
|
|
14
|
+
- Schedule recurring visibility checks, traffic syncs, and Business Profile syncs, with webhook alerts on regressions
|
|
15
|
+
- Generate client-ready HTML reports — `cnry report <project>`
|
|
16
|
+
- Drive from your own agent via the [67-tool MCP adapter](docs/mcp.md) or webhooks
|
|
17
|
+
- Or use **Aero** — Canonry's built-in agent that wakes up after every run
|
|
18
|
+
|
|
19
|
+
Every dashboard view has a matching CLI command and API endpoint. The CLI is the surface; the UI consumes the same API your agent does.
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
## Run your first AI visibility check in 5 minutes
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g @canonry/canonry
|
|
27
|
+
cnry init
|
|
28
|
+
cnry serve
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The CLI installs as `cnry` (short form) and `canonry` — the two are interchangeable.
|
|
32
|
+
The legacy package name `@ainyc/canonry` is still published at the same versions for compatibility, but new installs should use `@canonry/canonry`.
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
If you serve Canonry on `0.0.0.0` or a LAN address, complete first-run dashboard password setup from loopback first, or authenticate with a `cnry_...` bearer key. The unauthenticated setup path is loopback-only by design.
|
|
37
|
+
|
|
38
|
+
Prefer the terminal?
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cnry project create my-site --domain example.com
|
|
42
|
+
cnry query add my-site "your first query" "second query"
|
|
43
|
+
cnry run my-site --wait
|
|
44
|
+
cnry evidence my-site
|
|
45
|
+
cnry insights my-site
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Or set it up with your AI coding agent
|
|
49
|
+
|
|
50
|
+
Drop this into Claude Code, Codex, or any shell-capable agent. It installs canonry, runs your first sweep, audits your site for AEO readiness, and stops for your sign-off before taking any action on your behalf:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Set up canonry for me. Canonry is an open-source platform that tracks how AI answer engines (Gemini, ChatGPT, Claude, Perplexity) cite my site.
|
|
54
|
+
|
|
55
|
+
1. Ask me for: my domain, 3–5 queries I want to track, and which provider I want to start with (gemini / openai / claude / perplexity). Wait for my answers before proceeding.
|
|
56
|
+
2. Run `npm install -g @canonry/canonry`.
|
|
57
|
+
3. Run `cnry init` in this directory. This scaffolds config and installs the canonry skills into `.claude/skills/canonry/`, `.claude/skills/aero/`, `.codex/skills/canonry/`, and `.codex/skills/aero/`. If the skills aren't there afterwards, run `cnry skills install`.
|
|
58
|
+
4. Read the operator playbook at `.claude/skills/canonry/SKILL.md` and follow it end-to-end: create the project with my domain and queries, wire up the provider key I chose, and trigger the first sweep.
|
|
59
|
+
5. Open my browser to the dashboard so I can see the run results.
|
|
60
|
+
6. Switch to the analyst playbook at `.claude/skills/aero/SKILL.md` and run a baseline AEO audit on my behalf. Read citation evidence with `cnry evidence <project> --format json`, then run `cnry technical-aeo run <project> --wait` followed by `cnry technical-aeo score <project> --format json` for a site-readiness score. This crawls every page in my sitemap (not just the homepage), scores the whole site 0–100, and saves the result so it appears in the dashboard and can be re-audited on a schedule.
|
|
61
|
+
7. Summarize what you found: my mention and citation rates per provider, the top 3 queries I'm not yet cited on, and the highest-impact site issues from the audit. Ask me for permission before taking any further action, such as drafting content, submitting URLs for indexing, editing files, or anything else that changes my site.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
One-click copy at [canonry.ai](https://canonry.ai).
|
|
65
|
+
|
|
66
|
+
## If you get stuck
|
|
67
|
+
|
|
68
|
+
| Problem | Fix |
|
|
69
|
+
|---------|-----|
|
|
70
|
+
| No provider key configured | Open `/setup`, or grab a free [Gemini key](https://aistudio.google.com/apikey), set `GEMINI_API_KEY`, and restart `cnry serve`. |
|
|
71
|
+
| Why did my first audit fail? | Run `cnry doctor`, then reopen `/setup`; it checks provider keys and setup blockers before the first sweep. |
|
|
72
|
+
| No results after a run | Visibility checks are async — check the Runs tab or use `cnry run <project> --wait`. |
|
|
73
|
+
| Not sure what queries to test | Setup wizard auto-generates them; expand the basket later with `cnry discover run <project> --icp "..."` — see the [discovery methodology](skills/aero/references/aeo-discovery.md). |
|
|
74
|
+
| `npm install` fails on `node-gyp` | Install build tools for `better-sqlite3` ([guide](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/troubleshooting.md)). |
|
|
75
|
+
|
|
76
|
+
## Provider keys
|
|
77
|
+
|
|
78
|
+
| Provider | Key source | Env var |
|
|
79
|
+
|----------|-----------|---------|
|
|
80
|
+
| Gemini | [aistudio.google.com](https://aistudio.google.com/apikey) | `GEMINI_API_KEY` |
|
|
81
|
+
| OpenAI | [platform.openai.com](https://platform.openai.com/api-keys) | `OPENAI_API_KEY` |
|
|
82
|
+
| Claude | [console.anthropic.com](https://console.anthropic.com/settings/keys) | `ANTHROPIC_API_KEY` |
|
|
83
|
+
| Perplexity | [perplexity.ai/settings/api](https://www.perplexity.ai/settings/api) | `PERPLEXITY_API_KEY` |
|
|
84
|
+
| Local LLMs | Any OpenAI-compatible endpoint | `LOCAL_LLM_URL` |
|
|
85
|
+
|
|
86
|
+
Configure during `cnry init`, in the dashboard `/settings`, or as env vars.
|
|
87
|
+
|
|
88
|
+
## Documentation
|
|
89
|
+
|
|
90
|
+
| | |
|
|
91
|
+
|---|---|
|
|
92
|
+
| **Architecture & data model** | [docs/architecture.md](docs/architecture.md) · [docs/data-model.md](docs/data-model.md) |
|
|
93
|
+
| **Aero — built-in agent** | [skills/aero/SKILL.md](skills/aero/SKILL.md) |
|
|
94
|
+
| **MCP — Claude Desktop / Cursor / Codex** | [docs/mcp.md](docs/mcp.md) |
|
|
95
|
+
| **Integrations** | [GSC](docs/google-search-console-setup.md) · [GA4](docs/google-analytics-setup.md) · [Bing](docs/bing-webmaster-setup.md) · [Google Business Profile](skills/canonry/references/google-business-profile.md) · [WordPress](docs/wordpress-setup.md) · [Server-side traffic (Cloud Run + Vercel + WordPress logs)](skills/canonry/references/server-side-traffic.md) |
|
|
96
|
+
| **Deployment** — Docker, Railway, Render, systemd, Tailscale | [docs/deployment.md](docs/deployment.md) |
|
|
97
|
+
| **API** — 118+ endpoints | `GET /api/v1/openapi.json` (no auth) |
|
|
98
|
+
| **Skills bundle** for Claude Code / Codex | `cnry skills install` ([details](skills/canonry/SKILL.md)) |
|
|
99
|
+
| **Roadmap & ADRs** | [docs/roadmap.md](docs/roadmap.md) · [docs/adr/](docs/adr/) |
|
|
100
|
+
| **All docs** | [docs/README.md](docs/README.md) |
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
Node.js ≥ 22.14.0. At least one provider API key.
|
|
105
|
+
|
|
106
|
+
## Contributing
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/Canonry/canonry.git && cd canonry
|
|
110
|
+
pnpm install && pnpm run typecheck && pnpm run test && pnpm run lint
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
[FSL-1.1-ALv2](./LICENSE). Free to use, modify, and self-host. Each version converts to Apache 2.0 after two years.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Aero Agent -- Operational Guidelines
|
|
2
|
+
|
|
3
|
+
## Data Access
|
|
4
|
+
|
|
5
|
+
All data access goes through the canonry CLI. Never read the SQLite database directly.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Always use --format json for structured output
|
|
9
|
+
canonry <command> --format json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The canonry server must be running for most commands. Verify by hitting the health endpoint (`GET /health`) or by listing projects:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
canonry project list --format json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If the server isn't running, start it with `canonry serve`.
|
|
19
|
+
|
|
20
|
+
## Key Commands
|
|
21
|
+
|
|
22
|
+
### Monitoring
|
|
23
|
+
|
|
24
|
+
| Command | Purpose |
|
|
25
|
+
|---------|---------|
|
|
26
|
+
| `canonry run <project>` | Trigger a visibility sweep across all configured providers |
|
|
27
|
+
| `canonry run <project> --provider gemini` | Single-provider sweep |
|
|
28
|
+
| `canonry status <project>` | Current project status and latest run summary |
|
|
29
|
+
| `canonry evidence <project>` | Raw citation evidence from sweeps |
|
|
30
|
+
| `canonry insights <project>` | AI-generated insights and findings |
|
|
31
|
+
| `canonry health <project>` | Health snapshot with visibility scores |
|
|
32
|
+
| `canonry timeline <project>` | Per-query citation history over time |
|
|
33
|
+
| `canonry export <project>` | Full project data export |
|
|
34
|
+
|
|
35
|
+
### Auditing
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Run a technical AEO audit on a URL
|
|
39
|
+
npx @ainyc/aeo-audit <url> --format json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Project Management
|
|
43
|
+
|
|
44
|
+
| Command | Purpose |
|
|
45
|
+
|---------|---------|
|
|
46
|
+
| `canonry project list` | List all projects |
|
|
47
|
+
| `canonry project create <name> --domain <domain>` | Create a new project |
|
|
48
|
+
| `canonry query add <project> <query>...` | Add queries to track |
|
|
49
|
+
| `canonry query list <project>` | List tracked queries |
|
|
50
|
+
|
|
51
|
+
## Workflow Patterns
|
|
52
|
+
|
|
53
|
+
### Daily monitoring sweep
|
|
54
|
+
|
|
55
|
+
1. Check project status: `canonry status <project> --format json`
|
|
56
|
+
2. Run sweep if stale: `canonry run <project>`
|
|
57
|
+
3. Review insights: `canonry insights <project> --format json`
|
|
58
|
+
4. Escalate critical/high severity findings to the operator
|
|
59
|
+
|
|
60
|
+
### Investigation workflow
|
|
61
|
+
|
|
62
|
+
1. Identify affected queries from insights
|
|
63
|
+
2. Pull evidence: `canonry evidence <project> --format json`
|
|
64
|
+
3. Check timeline for trends: `canonry timeline <project> --format json`
|
|
65
|
+
4. If structural issues suspected, run audit: `npx @ainyc/aeo-audit <url> --format json`
|
|
66
|
+
5. Compile findings with evidence and recommended actions
|
|
67
|
+
|
|
68
|
+
## Quota Awareness
|
|
69
|
+
|
|
70
|
+
Provider APIs have rate limits. Follow these guidelines:
|
|
71
|
+
|
|
72
|
+
- Don't run full sweeps more than necessary. Check `canonry status` first to see when the last run completed.
|
|
73
|
+
- Use `--provider <name>` for targeted single-provider checks when investigating a specific engine.
|
|
74
|
+
- If a run returns `partial` status, some providers failed -- check the run details before retrying.
|
|
75
|
+
- Space out consecutive sweeps. Back-to-back runs waste quota without new data.
|
|
76
|
+
|
|
77
|
+
## Skills
|
|
78
|
+
|
|
79
|
+
Reference skills are available in `skills/` for domain-specific guidance:
|
|
80
|
+
|
|
81
|
+
- `skills/canonry/` -- Canonry operator playbook
|
|
82
|
+
|
|
83
|
+
## Error Handling
|
|
84
|
+
|
|
85
|
+
- Exit code `0` = success, `1` = user error, `2` = system error.
|
|
86
|
+
- On exit code `2` (system error), check server status and retry once before escalating.
|
|
87
|
+
- On exit code `1` (user error), review the error message -- don't retry the same command.
|
|
88
|
+
- Parse stderr for structured error JSON: `{ "error": { "code": "...", "message": "..." } }`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Client Context
|
|
2
|
+
|
|
3
|
+
This file stores client-specific context accumulated over time. Update it as you learn about the client's domain, priorities, and competitive landscape.
|
|
4
|
+
|
|
5
|
+
## Client Info
|
|
6
|
+
|
|
7
|
+
<!-- Domain, industry, target audience, key products/services -->
|
|
8
|
+
|
|
9
|
+
## Projects
|
|
10
|
+
|
|
11
|
+
<!-- Active canonry projects and their purpose -->
|
|
12
|
+
|
|
13
|
+
## Key Findings
|
|
14
|
+
|
|
15
|
+
<!-- Important discoveries from sweeps and audits, with dates -->
|
|
16
|
+
|
|
17
|
+
## Watchlist
|
|
18
|
+
|
|
19
|
+
<!-- Queries, competitors, or trends to monitor closely -->
|
|
20
|
+
|
|
21
|
+
## Notes
|
|
22
|
+
|
|
23
|
+
<!-- Any other relevant context -->
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aero
|
|
3
|
+
slug: aero
|
|
4
|
+
description: AEO analyst orchestration — coordinates canonry sweeps and aeo-audit analysis with persistent memory and proactive regression response.
|
|
5
|
+
homepage: https://canonry.ai
|
|
6
|
+
repository: https://github.com/AINYC/aero
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Aero Orchestration Skill
|
|
10
|
+
|
|
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**, **server-side crawler + referral events**). 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. For a specific scalar use `cnry get <project> <path>` instead of pulling a full payload.
|
|
13
|
+
- **aeo-audit** — on-demand site analysis and fix generation.
|
|
14
|
+
|
|
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
|
+
|
|
17
|
+
**Two signals, not one.** Every (query × provider) snapshot tracks **mentioned** (brand in answer text) and **cited** (domain in source links) independently. Lead with **Mention Coverage** when narrating health — it is the primary gauge — and report **Citation Coverage** as the secondary signal. Never compute one from the other, and never collapse them into a single "visibility" headline. The downloadable report (`cnry report`) and the dashboard hero both honor this split.
|
|
18
|
+
|
|
19
|
+
When a project has GA4 connected, traffic is a first-class signal alongside mentions and 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. When the project has a server-side traffic source attached (Cloud Run / WordPress / Vercel), `cnry traffic status` and `cnry traffic events` surface crawler + AI-referral evidence the GA4 layer can miss. Full command reference and return shapes live in the co-installed `canonry/references/canonry-cli.md`.
|
|
20
|
+
|
|
21
|
+
**Diagnosing a stuck Vercel/Cloud Run source:** if `cnry traffic status` shows `status=error` with a recent `lastError` of `refusing to advance` or `ExceedsBillingLimitError`, the source's `lastSyncedAt` has aged past the upstream retention boundary and every sync now throws. Recovery: `cnry traffic reset <project> --source <id> --advance-to-now`. This advances `lastSyncedAt` to NOW and resumes going-forward syncs — historical events in the gap are unrecoverable from the sync path; run `cnry traffic backfill --days N` separately if any of that history is needed (capped at retention).
|
|
22
|
+
|
|
23
|
+
## Judgment Rules
|
|
24
|
+
|
|
25
|
+
### What to Prioritize
|
|
26
|
+
|
|
27
|
+
Mention is the primary gauge (see "Two signals, not one" above); citation is the secondary signal on the same query. Rank work accordingly:
|
|
28
|
+
|
|
29
|
+
1. **Branded-term mention loss** — the engine no longer MENTIONING your brand by name is the most urgent regression. Losing the citation for your own name is the secondary signal on the same query: report it, but the mention is what moved share.
|
|
30
|
+
2. **Mention-share losses** — a competitor took mention share on a query where yours fell. Rank by share swing first, then by any lost citation on the same query.
|
|
31
|
+
3. **Neither mentioned nor cited** — new queries where you are absent on both signals (not mentioned and not cited). Mention gap leads; the missing citation is the trailing clause.
|
|
32
|
+
4. **Indexing issues** — pages not indexed can't be cited, and a weak/unindexed page also starves the engine of reasons to mention you. Keep this on the list; it feeds both signals.
|
|
33
|
+
5. **Content optimization** — improve mention rate first (give the answer a reason to name you), then cited rate on partially-covered queries.
|
|
34
|
+
|
|
35
|
+
### What NOT to Do
|
|
36
|
+
- Don't promise fixes will appear in the next sweep (AEO changes take weeks/months)
|
|
37
|
+
- Don't give generic SEO advice — always ground recommendations in mention and citation data, leading with the mention signal
|
|
38
|
+
- Don't run sweeps without user confirmation (they consume API quota)
|
|
39
|
+
- Don't edit client's code without showing diffs and getting approval
|
|
40
|
+
- Don't conflate "not mentioned" with "page doesn't exist" — and don't conflate "not cited" with "not mentioned" either; check first. The two signals are independent (see "Two signals, not one") and are never computed from each other.
|
|
41
|
+
- Don't coerce `answerMentioned` null → false. Null means "not checked," not "not mentioned" — treat it as missing data, never as a negative.
|
|
42
|
+
|
|
43
|
+
### When to use `--probe` runs
|
|
44
|
+
When you need to **verify** something on your own initiative — "did the OpenAI provider migration land cleanly?", "is the regression still reproducible after the WP fix?", "does this query actually surface us when I think it should?" — use `cnry run <project> --probe --provider <p> --query "..."`. Probe runs:
|
|
45
|
+
- Still cost provider API quota (same wire call)
|
|
46
|
+
- Write a snapshot you can inspect via `cnry runs get <id>`
|
|
47
|
+
- Are EXCLUDED from dashboard, analytics, intelligence, insights, and notifications
|
|
48
|
+
- Won't wake you up again via the post-run hook (no recursive analysis loops)
|
|
49
|
+
|
|
50
|
+
Use probes whenever the run is for **your** investigation, not for the user's metrics. The two May-17 ainyc probes that broke the dashboard before this convention existed are the canonical example of why this matters — a 1-snapshot test masqueraded as "the latest sweep" and zeroed the headline.
|
|
51
|
+
|
|
52
|
+
A real (non-probe) sweep is appropriate when the user explicitly asks to refresh data ("run it again", "get the latest", "trigger a sweep").
|
|
53
|
+
|
|
54
|
+
### How to Communicate
|
|
55
|
+
- Data first: show the numbers before the interpretation
|
|
56
|
+
- Lead with the mention transition, keep citation as a trailing clause: "ChatGPT stopped mentioning you for 'roof repair phoenix' between Mar 28-Apr 2, and your mention share fell from 50% to 0% as a competitor took the slot" — then, second, note that you also lost the citation for that query. Not "your visibility decreased."
|
|
57
|
+
- Action-oriented: every observation ends with a recommended next step
|
|
58
|
+
|
|
59
|
+
## References
|
|
60
|
+
|
|
61
|
+
Detailed playbooks live alongside this file. Read them on demand when the task matches:
|
|
62
|
+
|
|
63
|
+
| File | Read when |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `references/orchestration.md` | Planning a multi-step or recurring workflow (baseline, weekly review, content-gap analysis) |
|
|
66
|
+
| `references/regression-playbook.md` | A query lost a mention (primary) or a citation (secondary) and you need to triage and respond |
|
|
67
|
+
| `references/aeo-discovery.md` | Expanding a tracked-query basket, auditing competitive surface, or responding to `aeo-discover-probe.completed` |
|
|
68
|
+
| `references/memory-patterns.md` | Deciding whether to remember a fact in agent memory or re-query canonry |
|
|
69
|
+
| `references/reporting.md` | Producing a client-facing weekly or monthly summary |
|
|
70
|
+
| `references/wordpress-elementor-mcp.md` | Editing WordPress pages with the Elementor MCP integration |
|
|
71
|
+
|
|
72
|
+
Aero (canonry's built-in agent) additionally exposes `list_skill_docs` / `read_skill_doc` MCP tools that walk this directory programmatically. External agents (Claude Code, Codex) should `Read` the files directly.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aeo-discovery
|
|
3
|
+
description: How to operate the tracked-basket discovery pipeline. Read when an operator asks to expand a project's basket, audit its competitive surface, or you wake unprompted on `aeo-discover-probe.completed`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AEO Discovery (Tracked-Basket Expansion)
|
|
7
|
+
|
|
8
|
+
Discovery turns a free-text ICP description into a deduped basket of representative queries, probes each against Gemini grounding, and classifies the results into three buckets. Read each bucket as **mention-or-citation** presence — the brand named in the answer text (`answerMentioned`, the primary signal) OR the domain in the grounding sources (`cited`, the secondary signal) — not citation alone:
|
|
9
|
+
|
|
10
|
+
- **cited** — the project shows up for the query: its brand is mentioned in the answer text, or its canonical/owned domain appears in the grounding sources (mention-or-citation present)
|
|
11
|
+
- **wasted-surface** — a tracked competitor shows up (mentioned or cited) but the project does not
|
|
12
|
+
- **aspirational** — neither the project nor a tracked competitor shows up on either signal (greenfield)
|
|
13
|
+
|
|
14
|
+
Plus a competitor map: every non-canonical domain (and named competitor brand) that shows up across probes, ranked by hit count and classified by type, so the operator can spot recurring competitors that aren't yet on the watchlist. Read the headline competitor signal as mention-or-citation, not citation alone — a competitor the engine keeps NAMING is taking your share of voice even when no domain is cited.
|
|
15
|
+
|
|
16
|
+
> **Mention data on probes (engine PR #707, merged 2026-06-17).** Discovery probes now carry `answerMentioned` per probe, so mention-based bucketing and competitor reads are available. Sessions that pre-date #707 have `answerMentioned = null` on their probes — read null as "not checked," never as not-mentioned, and fall back to the cited signal for those older sessions.
|
|
17
|
+
|
|
18
|
+
After probing, one Gemini call classifies every recurring cited domain into a `competitorType`:
|
|
19
|
+
|
|
20
|
+
- **direct-competitor** — a business competing for the same customers (another hotel, another tool in the category). The only type promoted by default.
|
|
21
|
+
- **ota-aggregator** — OTAs, marketplaces, directories, review aggregators (expedia.com, booking.com, g2.com). Suppressed from competitor tracking.
|
|
22
|
+
- **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.
|
|
23
|
+
- **other** — government sites, social platforms, off-topic domains. Suppressed.
|
|
24
|
+
- **unknown** — classification failed, or a session that pre-dates classification. Excluded from the default promote.
|
|
25
|
+
|
|
26
|
+
## When discovery is the right move
|
|
27
|
+
|
|
28
|
+
- Operator says "expand my tracked queries", "audit my basket", "what am I missing", "find competitors I should track".
|
|
29
|
+
- Recurring `wasted-surface` shows up in regression analysis — the project keeps losing on queries adjacent to its tracked basket.
|
|
30
|
+
- A new ICP is being onboarded and the operator only has a domain + tagline, no curated query list.
|
|
31
|
+
|
|
32
|
+
## Triggering a session
|
|
33
|
+
|
|
34
|
+
The operator runs:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cnry discover run <project> --icp "..." --wait
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
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`.
|
|
41
|
+
|
|
42
|
+
ICP fallback: if the request omits `icpDescription`, the route uses `projects.icp_description` if set. Surface a clear "needs an ICP" prompt if neither is available.
|
|
43
|
+
|
|
44
|
+
## Cost + budget
|
|
45
|
+
|
|
46
|
+
Per session: ~$1 at the default probe budget (100 queries × 1 Gemini grounded call each, plus a single batched embed call for ~$0.0002). Hard cap: 500 probes per session, enforced both client-side (Zod) and server-side. Recommend the default (100) unless the operator has a specific reason.
|
|
47
|
+
|
|
48
|
+
## Reading the result
|
|
49
|
+
|
|
50
|
+
`canonry_discover_session_get` returns:
|
|
51
|
+
|
|
52
|
+
- Session-level: `seedCountRaw` vs `seedCount` (proves embedding dedup did real work), bucket counts, `competitorMap` (top recurring non-tracked domains, each with `hits` and `competitorType`).
|
|
53
|
+
- Per-probe: query, bucket, citation state, the cited domains list.
|
|
54
|
+
|
|
55
|
+
Things to call out without being asked:
|
|
56
|
+
|
|
57
|
+
- **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.
|
|
58
|
+
- **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.
|
|
59
|
+
- **Aspirational greenfield** queries with no tracked competitor and no canonical cite → low-friction content opportunities.
|
|
60
|
+
|
|
61
|
+
## Promoting a session into the tracked basket
|
|
62
|
+
|
|
63
|
+
Once a session is `completed`, preview first unless the operator has already approved the write:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cnry discover promote preview <project> <session-id>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or the MCP equivalent: `canonry_discover_promote_preview` with `{ project, sessionId }`.
|
|
70
|
+
|
|
71
|
+
The preview returns every bucket so you can explain the tradeoff:
|
|
72
|
+
|
|
73
|
+
- `cited` — already grounded to the project, safe to track.
|
|
74
|
+
- `aspirational` — greenfield ICP-fit opportunities, safe to track as a growth basket.
|
|
75
|
+
- `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.
|
|
76
|
+
- `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.
|
|
77
|
+
|
|
78
|
+
Promote with one of these paths:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cnry discover promote <project> <session-id> # cited + aspirational buckets + direct-competitor domains
|
|
82
|
+
cnry discover promote <project> <session-id> --bucket aspirational # scope to a bucket subset (repeatable / comma-separated)
|
|
83
|
+
cnry discover promote <project> <session-id> --bucket wasted-surface # explicitly track off-ICP competitor gaps
|
|
84
|
+
cnry discover promote <project> <session-id> --competitor-types direct-competitor,editorial-media # widen the competitor merge to other classified types
|
|
85
|
+
cnry discover promote <project> <session-id> --no-competitors # queries only, skip the competitor merge
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Or the MCP equivalent:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{ "project": "<project>", "sessionId": "<session-id>" }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
That default request promotes `cited` + `aspirational` queries and `direct-competitor` domains. For scoped writes, pass `request`:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "project": "<project>", "sessionId": "<session-id>", "request": { "buckets": ["aspirational"], "competitorTypes": ["direct-competitor", "editorial-media"], "includeCompetitors": false } }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- **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.
|
|
101
|
+
- **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.
|
|
102
|
+
- **Add-only and idempotent.** Queries and competitor domains already tracked are returned under `skipped`, never inserted twice. Re-running a promote is safe.
|
|
103
|
+
- **Completed sessions only.** Promoting a `queued`/`seeding`/`probing`/`failed` session is rejected — the buckets aren't final.
|
|
104
|
+
- Promoted rows carry `provenance="discovery:<sessionId>"`, so a tracked query can always be traced back to the session that surfaced it.
|
|
105
|
+
|
|
106
|
+
## When you wake on `aeo-discover-probe.completed`
|
|
107
|
+
|
|
108
|
+
The follow-up payload `RunCoordinator` queues for you includes:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
[system] Discovery run <runId> completed for project <name> (session <sessionId>).
|
|
112
|
+
Buckets — cited:<n>, wasted-surface:<n>, aspirational:<n> (<probeCount> probes; seed provider: gemini).
|
|
113
|
+
Top recurring competitor domains: <domain1>(<hits>), <domain2>(<hits>), …
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Respond with:
|
|
117
|
+
|
|
118
|
+
1. A one-line headline naming the dominant bucket.
|
|
119
|
+
2. The top 2-3 wasted-surface queries (call `canonry_discover_session_get` to fetch them — don't guess).
|
|
120
|
+
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.
|
|
121
|
+
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".
|
|
122
|
+
|
|
123
|
+
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.
|
|
124
|
+
|
|
125
|
+
Keep it tight. The operator wakes to a short, decision-ready summary, not a full report.
|
|
126
|
+
|
|
127
|
+
## What discovery does NOT do (yet)
|
|
128
|
+
|
|
129
|
+
- **No multi-provider amplification.** v1 probes Gemini only. v2 will probe across Gemini + ChatGPT + Claude in one session (the schema is already shaped for it — `discovery_probes` has no `UNIQUE(session_id, query)` exactly because of this).
|
|
130
|
+
- **No re-run drift.** Each session is independent. Comparing sessions over time is on the PR 4 / PR 5 roadmap.
|
|
131
|
+
|
|
132
|
+
## Failure modes
|
|
133
|
+
|
|
134
|
+
- **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`.
|
|
135
|
+
- **Vertex-only Gemini** → embeddings step throws (Vertex embeddings deferred). Same surface, "use a Gemini API key for now."
|
|
136
|
+
- **ICP missing** → route returns 400 with `VALIDATION_ERROR`. Ask the operator for the ICP description in plain language.
|
|
137
|
+
- **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.
|
|
138
|
+
|
|
139
|
+
**Diagnostic signal:** `seedCountRaw / seedCount > 10:1` (e.g. 40 raw → 1 selected).
|
|
140
|
+
|
|
141
|
+
**Remediation:** break the ICP into 3-5 distinct purchase-intent angles and run one session per angle via `--icp-angle`:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cnry discover run <project> \
|
|
145
|
+
--icp-angle "romantic anniversary stay in Venice Beach" \
|
|
146
|
+
--icp-angle "best rooftop bars and dining hotels LA" \
|
|
147
|
+
--icp-angle "walkable Venice Beach hotels near Abbot Kinney" \
|
|
148
|
+
--icp-angle "design-forward boutique hotels for creative professionals" \
|
|
149
|
+
--wait
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Each angle generates its own 40-seed cluster independently, so aggregate coverage grows while per-session dedup stays clean. The `--wait` output prints a combined summary with per-session session IDs and a `promote` command for each. Promote the sessions individually after reviewing previews.
|
|
153
|
+
|
|
154
|
+
## Memory hygiene
|
|
155
|
+
|
|
156
|
+
After a discovery session, store a one-liner in `agent_memory` if the operator validates a non-obvious call. Examples:
|
|
157
|
+
|
|
158
|
+
- `discovery:icp-style` — phrasing they responded well to
|
|
159
|
+
- `discovery:competitor-watchlist` — domains they explicitly accepted/rejected from the suggested list
|
|
160
|
+
|
|
161
|
+
Skip routine results — only memory-worthy material is what would help a future session avoid re-asking the same question.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-patterns
|
|
3
|
+
description: When to remember vs. re-query — project state lives in canonry, only durable user-scoped facts go in Aero memory. Read when unsure whether to call canonry_memory_set or look up.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Patterns
|
|
7
|
+
|
|
8
|
+
Canonry is the source of truth for project state. Do **not** maintain a parallel copy of project facts in Aero memory — it will drift from the DB and mislead the next session.
|
|
9
|
+
|
|
10
|
+
Aero ships with a built-in durable notes store — the `canonry_memory_set`, `canonry_memory_forget`, and `canonry_memory_list` tools — backed by the `agent_memory` table. The N most-recently-updated notes are injected into the system prompt at every session start, so you usually see relevant memory without calling `canonry_memory_list`.
|
|
11
|
+
|
|
12
|
+
## What belongs where
|
|
13
|
+
|
|
14
|
+
| Scope | Examples | Home |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **Project state** | Baselines (**mention rate + mention share** as the primary KPI, then cited rate), historical regressions, mention + citation rates per query/provider, recent insights, sweep history, audit trail | Canonry DB — query via CLI / API / read tools |
|
|
17
|
+
| **Operator facts** | Personal preferences, non-observable context ("content lead is Sarah", "migrating off Webflow next quarter"), tone/voice preferences the operator confirmed | Aero memory (`canonry_memory_set`) |
|
|
18
|
+
| **Session scratch** | "I just tried X and it failed", intermediate reasoning, turn-local state | Nowhere — let it die with the session |
|
|
19
|
+
|
|
20
|
+
## How to read project state from canonry
|
|
21
|
+
|
|
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
|
+
|
|
24
|
+
```bash
|
|
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
|
+
```
|
|
32
|
+
|
|
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.
|
|
34
|
+
|
|
35
|
+
## Regenerate, don't remember
|
|
36
|
+
|
|
37
|
+
Derived interpretations (trend summaries, correlations between events) are cheap to recompute from the underlying DB rows. Prefer running the analysis again on fresh data over recalling what you concluded last session — conclusions age, the data doesn't.
|
|
38
|
+
|
|
39
|
+
## Using `canonry_memory_set` / `canonry_memory_forget` / `canonry_memory_list`
|
|
40
|
+
|
|
41
|
+
- `canonry_memory_set({ key, value })` — upsert a project-scoped note. Capped at 2 KB per value. Same key replaces the prior value, so use stable keys (e.g. `operator-pref.reporting-tone`, not `note-2026-04-17`).
|
|
42
|
+
- `canonry_memory_forget({ key })` — remove a single note. Returns `status: missing` when the key never existed (non-fatal).
|
|
43
|
+
- `canonry_memory_list()` — read notes newest-first. Usually unnecessary — the top 20 are already in the system prompt under `<memory>`. Reach for it when you need older context or the full value of a note that's been summarized.
|
|
44
|
+
|
|
45
|
+
**Reserved prefix.** Keys starting with `compaction:` are reserved for LLM-summarized transcript slices. `canonry_memory_set` and `canonry_memory_forget` both reject them. Compaction notes are pruned automatically — you can list them but never write or delete them by hand.
|
|
46
|
+
|
|
47
|
+
**CLI parity.** Operators can manage memory without talking to you:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
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
|
+
```
|
|
54
|
+
|
|
55
|
+
## Good remember candidates
|
|
56
|
+
|
|
57
|
+
- Operator-confirmed facts canonry can't observe (team names, migration plans, vendor lock-in, upcoming content bets).
|
|
58
|
+
- Stable preferences the operator has validated at least once ("report weekly", "prefer Claude over GPT for prose", "never auto-dismiss insights").
|
|
59
|
+
- Non-obvious decisions made mid-investigation that a future turn would re-derive wastefully ("confirmed competitor X is out of scope").
|
|
60
|
+
|
|
61
|
+
## Bad remember candidates
|
|
62
|
+
|
|
63
|
+
- Anything canonry already tracks (runs, insights, citation rates, schedules). Query it.
|
|
64
|
+
- Turn-local state that's useful for one follow-up and then noise ("user just asked about query Y").
|
|
65
|
+
- Raw evidence or long transcripts — persist a conclusion, not a dump.
|
|
66
|
+
- Unvalidated guesses. Memory isn't a place to think aloud; it's a place to record things you're willing to act on next session.
|