aeo-audit
CLAUDE.md6 starsChanged 4 days agoMITView on GitHub
@canonry/agent-readiness — an open-source website agent readiness audit engine and single umbrella Claude Code / ClawHub skill. Scores how well AI agents and answer engines can reach, read, and cite a site across 16 factors. Formerly @canonry/aeo-audit (and @ainyc/aeo-audit before that); the CHANGELOG keeps the old names in past entries. Website: https://canonry.ai Any change to user-visible CLI surface must update all three of these in the same change: This applies to:
- Installs packages
In this repository2 other files it gives its agents.
- docsSkill
- agent-readinessSkill
The file
We split this CLAUDE.md into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 63
Always use clampScore() for score calculations
- Very specific: line 82
Before opening a PR that touches src/cli.ts, grep docs/cli.md and SKILL.md for the affected flag name to confirm everything still matches.
- Very specific: line 102
Only needed if the workflow failed, and rerunning it (workflow_dispatch on main) is usually the better fix.
- Distinctive: line 123
Single trigger path per release flow: If the workflow auto-creates a tag, do not also trigger on that tag pattern — the self-pushed tag …
- Very specific: line 124
Never interpolate step outputs directly into
run:blocks: Use an env: block to pass values into shell scripts: env: { VERSION: "${{ … - Very specific: line 125
Scope permissions to the minimum required per job: If only one step needs contents: write (e.g., pushing a tag), prefer splitting it into a …
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
Project Overview
@canonry/agent-readiness — an open-source website agent readiness audit engine and single umbrella Claude Code / ClawHub skill. Scores how well AI agents and answer engines can reach, read, and cite a site across 16 factors. Formerly @canonry/aeo-audit (and @ainyc/aeo-audit before that); the CHANGELOG keeps the old names in past entries.
Website: https://canonry.ai
Tech Stack
- Language: TypeScript (ESM)
- Runtime: Node.js >= 20
- Package manager: pnpm
- HTML parsing: Cheerio
- Build: TypeScript compiler to
dist/ - Typecheck:
tsc --noEmit - Test runner:
tsx --test - Linter: ESLint v9 flat config
Commands
pnpm install # Install dependencies
pnpm run typecheck # Static typecheck
pnpm run build # Compile src/*.ts to dist/
pnpm test # Run all tests
pnpm lint # Run linterKey Files
src/
index.ts # Main entry: runAgentReadinessAudit(url, options)
scoring.ts # Factor definitions, weights, score calculation
fetch-page.ts # URL fetching with SSRF protection
errors.ts # AgentReadinessError class
cli.ts # CLI argument parsing
formatters/ # json, markdown, text output formatters
analyzers/ # Per-factor analyzer modules (16 core + 2 optional) plus shared helpers.ts
types.ts # Shared audit/report TypeScript types
dist/ # Compiled publishable ESM output
bin/
agent-readiness.js # CLI entry point -> dist/cli.js
skills/agent-readiness/ # Single umbrella Claude Code / ClawHub skill
test/ # Unit and integration testsArchitecture
- Each analyzer receives a context object
{ $, html, url, headers, auxiliary, structuredData, textContent, pageTitle }and returns{ score, findings, recommendations } - Scores are weighted and normalized in
scoring.ts. Weights are RELATIVE and do NOT sum to 100 (the core set sums to 111); the score divides by the actual total of the factors it scored. Each factor carriessharePct, its real share of the score. Never presentweightas a percentage - A factor an analyzer reports
applicable: falsefor is excluded from the score entirely, weight and all (factorAppliesinscoring.ts), so a page is not marked down for lacking something it has no reason to have - Geographic signals is optional (excluded by default); when included, weights renormalize
- The
--factorsflag allows running a subset of analyzers - SSRF protection blocks private IPs and hostnames in
fetch-page.ts - The crawler's network identity (User-Agent
AINYC-AEO-Audit/1.0infetch-page.ts, robots.txt tokenainyc-aeo-auditincrawl.ts) is deliberately unchanged across package renames. Sites may have robots.txt rules for it, and Canonry drops traffic with that User-Agent from client traffic reports. Never rename it as part of a branding change - Published entrypoints resolve to compiled
dist/output; runpnpm run buildbefore local CLI smoke tests
Code Conventions
- Functional style, no classes except AgentReadinessError
- Always use
clampScore()for score calculations - Findings types:
found,missing,info,timeout,unreachable - Unused vars starting with
_are ignored by ESLint
Documentation
Any change to user-visible CLI surface must update all three of these in the same change:
printHelp()insrc/cli.ts— Options list and Examples blockdocs/cli.md— the relevant mode section, the Flag reference table, and the Exit codes section (flags, examples, and any defaults). The rootREADME.mdonly carries a handful of headline examples; the full CLI surface lives indocs/cli.md.skills/agent-readiness/SKILL.md— Examples and the relevant mode section (e.g.### Sitemap Mode)
This applies to:
- Adding, renaming, or removing a flag
- Changing a default value (e.g. sitemap
--limitdefault of 200) — the default must be stated in the help string,docs/cli.md, and SKILL.md - Adding a new CLI mode (e.g.
--sitemap) — document flags, defaults, exit-code behavior, and an example invocation in all three places - Changing exit-code semantics or output format options
Before opening a PR that touches src/cli.ts, grep docs/cli.md and SKILL.md for the affected flag name to confirm everything still matches.
The README's terminal image (docs/images/readme/hero.svg) is rendered from a real audit of test/fixtures/site. When a change alters the text report (src/formatters/text.ts, factor names, or scoring of the sample site), regenerate it with pnpm run build && node scripts/render-readme-hero.mjs.
Versioning
Follows semver. Bump version in package.json on every change that ships:
- Patch (
1.3.x) — bug fixes, scoring corrections, internal refactors with no API change - Minor (
1.x.0) — new analyzers, new CLI flags, new exported helpers (backwards-compatible) - Major (
x.0.0) — breaking changes to the public API or scoring weights that would change existing audit results
The ClawHub skill version must match package.json.
ClawHub Publishing
CI publishes the skill; there is no manual step. When a push to main changes the version in package.json, .github/workflows/publish.yml publishes the npm package and then runs clawhub publish skills/agent-readiness with that version and the commit subject as the changelog. A skills/agent-readiness/SKILL.md change therefore ships with the next version bump.
Publishing by hand
Only needed if the workflow failed, and rerunning it (workflow_dispatch on main) is usually the better fix. To publish by hand anyway, from the repo root:
clawhub whoami # should print your handle (e.g. arberx); if not, run `clawhub login`
clawhub publish skills/agent-readiness --version <semver> --changelog "<description of changes>"--version must be valid semver and must match package.json.
ClawHub Security Guidelines
ClawHub flags skills as suspicious when they request excessive capabilities. Follow these rules to stay under the threshold:
- Pin npx versions — use the current major (
@8) instead of@latest. The@latesttag is a supply chain risk because a compromised publish can hijack all users immediately. Never pin an exact version (@8.0.0): the major pin already gives users every patch and minor release without a skill update. Bump it only in the release that changes the major. - Minimize Bash patterns — only declare the single npx command end users need. Do not include local dev commands (
pnpm run build,node bin/...) in the published skill; those are for contributors, not consumers. - Avoid generic Bash patterns —
Bash(agent-readiness *)is too broad and could match other binaries. Always use the fully qualifiednpx @canonry/agent-readiness@8 *form. - Scope file permissions narrowly — only request Edit/Write for file types the skill actually modifies. Use
Write(filename)for specific files (e.g.,llms.txt,robots.txt) instead of broadEdit(*.txt)patterns. - Keep shell injection guards — the Argument Safety section in SKILL.md is required. Never remove it.
GitHub Actions Conventions
- Single trigger path per release flow. If the workflow auto-creates a tag, do not also trigger on that tag pattern — the self-pushed tag will re-fire the workflow, causing a duplicate publish that fails with 403 on npm.
- Never interpolate step outputs directly into
run:blocks. Use anenv:block to pass values into shell scripts:env: { VERSION: "${{ steps.x.outputs.version }}" }then reference$VERSIONin the script. Direct${{ }}interpolation inrun:is a script-injection vector. - Scope permissions to the minimum required per job. If only one step needs
contents: write(e.g., pushing a tag), prefer splitting it into a separate job with its own permissions block rather than elevating the entire job. - Declare explicit
permissionson every job. Omitting thepermissionsblock inherits the repository default, which may bewrite-all. Always declare at minimumcontents: read.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

