diff --git a/CHANGELOG.md b/CHANGELOG.md index eea57ff..9ef740f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - Docs: each `docs/` page opens with a paragraph naming its reader and purpose. - Docs: `docs/testing.md` adds a `/humanize` smoke test and checks that `/docs-lint-setup` copies the `ai-tells` style. - Docs: `docs/versioning.md` adds a release step to update the README version badge. +- Docs: `README.md` drops the `Status` column from `Components` and folds `The rule that defines it` into `How it decides`. +- Docs: `README.md` adds `Routing` and `Cursor parity` features, a grounding-sources paragraph, and a `Components` row for `references/vale.ini`. +- Docs: `README.md` states that both agents hold `Bash` but not `Write` or `Edit`. ### Fixed - Docs: `docs/install.md` no longer lists `go install` as a Vale install route, and names one prose linter instead of two. - Docs: `docs/testing.md` says to load a working copy with `--plugin-dir`, not install it. +- Docs: `README.md` limits the claims-rule feature to the skills that write or edit prose. +- Docs: `README.md` credits the read-the-repo-first step to the router and Cursor rule, not to every skill. +- Docs: `docs/install.md` names the Cursor-only rule among host differences and the `_vale.ini` alternative. +- Docs: `docs/testing.md` says a missing agent `tools:` key is an error too. +- Docs: `docs/testing.md` says CI runs `scripts/validate.py` directly, not `scripts/validate.sh`. +- Docs: `docs/authoring.md` lists `ai-tells.md` among the references. +- Docs: `docs/install.md` calls the prose-lint hook by name instead of "save hook". ## [0.4.0] - 2026-09-24 diff --git a/README.md b/README.md index 13dea62..1128f1d 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,21 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Version](https://img.shields.io/badge/version-0.4.0-blue)](CHANGELOG.md) -[![Claude Code](https://img.shields.io/badge/Claude_Code-plugin-D97757?logo=anthropic&logoColor=white)](https://claude.ai/code) +[![Claude Code](https://img.shields.io/badge/Claude_Code-plugin-D97757?logo=anthropic&logoColor=white)](https://docs.claude.com/en/docs/claude-code/overview) [![Cursor](https://img.shields.io/badge/Cursor-plugin-000?logo=cursor&logoColor=white)](https://cursor.com) [![Keep a Changelog](https://img.shields.io/badge/Keep%20a%20Changelog-1.1.0-E05735)](CHANGELOG.md) -An AI plugin by **Cadasto B.V.** that teaches AI coding assistants documentation, editing, and content standards: technical writing, copy editing, AI-tell cleanup, marketing copy, SEO, and AI citability. It is for anyone who has an assistant write or edit human-facing docs. It adds eight skills, two report-only review agents, a session-start hook, a prose-lint hook, and a Cursor rule, shared by **Claude Code** and **Cursor** from one component set. +An AI plugin by **Cadasto B.V.** that teaches AI coding assistants documentation, editing, and content standards: technical writing, copy editing, AI-tell cleanup, marketing copy, SEO, and AI citability. It is for anyone who has an assistant write or edit human-facing docs. It adds eight skills, two report-only review agents, and two hooks (session-start, prose-lint) for **[Claude Code](https://docs.claude.com/en/docs/claude-code/overview)** and **[Cursor](https://cursor.com)** from one shared component set, plus a Cursor rule. -The plugin owns the prose and content layer, and one rule defines it: a claim that cannot be traced to a source does not ship ([why](#the-rule-that-defines-it)). It reads agent-instruction files (`AGENTS.md`, `CLAUDE.md`, rule files, skill and agent definitions) for a repository's conventions but never writes them. It does not review source code, and it leaves specification, requirement, and traceability authoring to the `sdd` plugin. Domain facts come from the target repository's named ground-truth source, never from the plugin. +The plugin owns the prose and content layer, and one rule defines it: a claim that cannot be traced to a source does not ship ([how it decides](#how-it-decides)). It reads agent-instruction files (`AGENTS.md`, `CLAUDE.md`, rule files, skill and agent definitions) for a repository's conventions but never writes them. It does not review source code, and it leaves specification, requirement, and traceability authoring to the `sdd` plugin. Domain facts come from the target repository's named ground-truth source, never from the plugin. -**Requirements.** A Claude Code or Cursor host; nothing else. The skills apply the standards by judgment with no tooling installed. To make the prose rules machine-enforced, install [Vale](https://vale.sh) and run `/docs-lint-setup` in your repository; see [Host toolchain](docs/install.md#host-toolchain-optional-but-recommended). Without Vale the prose-lint hook stays silent. The plugin is pure Markdown + JSON, with no build step and no MCP server. +**Requirements.** A Claude Code or Cursor host. The plugin is pure Markdown + JSON, with no build step and no MCP server, and the skills apply the standards by judgment with no other tooling installed. To have the prose rules checked by a linter, install [Vale](https://vale.sh) and run `/docs-lint-setup` in your repository; until both are in place, the prose-lint hook stays silent. See [Host toolchain](docs/install.md#host-toolchain-optional-but-recommended) for install options. ## Table of contents - [Features](#features) - [Installation](#installation) - [Components](#components) -- [The rule that defines it](#the-rule-that-defines-it) - [How it decides](#how-it-decides) - [Development](#development) - [Documentation](#documentation) @@ -25,12 +24,14 @@ The plugin owns the prose and content layer, and one rule defines it: a claim th ## Features -- **Evidence before persuasion**: every skill replaces an invented statistic, testimonial, or superlative with the observable mechanism, per [`references/claims-and-evidence.md`](references/claims-and-evidence.md). +- **Routing**: you describe the prose task; the auto-invoked `docs-editing` router picks the skill for it. +- **Evidence before persuasion**: the skills that write or edit prose refuse to invent a statistic, testimonial, or superlative, and `/copy-editing` and `/marketing-copy` replace one they find with the observable mechanism, per [`references/claims-and-evidence.md`](references/claims-and-evidence.md). - **Writing and editing**: `/technical-writing` drafts new docs in one document kind, `/copy-editing` tightens existing prose under a stated contract, and `/humanize` removes AI tells. -- **Marketing copy**: `/marketing-copy` writes landing, feature, and announcement copy for technical readers, with the anti-fabrication guardrails applied before drafting. +- **Marketing copy**: `/marketing-copy` writes pitch copy for technical readers without invented metrics or testimonials. - **Discoverability**: `/seo-audit` audits the published output for search engines; `/ai-seo` covers `llms.txt`, Markdown twins, and JSON-LD. - **Prose linting**: `/docs-lint-setup` scaffolds Vale with the `ai-tells` style, and the prose-lint hook reports Vale alerts after each Markdown edit without rewriting the file. -- **Independent review**: the report-only `prose-reviewer` and `seo-auditor` agents return ranked findings in an isolated context. +- **Review**: the report-only `prose-reviewer` and `seo-auditor` agents return ranked findings from an isolated context. +- **Cursor parity**: Cursor gets the same skills, agents, and hooks, plus `rules/docs-editing-context.mdc` mirroring the router. ## Installation @@ -43,72 +44,71 @@ The plugin owns the prose and content layer, and one rule defines it: a claim th Or load a local working copy for a single session: `claude --plugin-dir /path/to/docs-editing-plugin`. -**Cursor**: add this repository through Cursor's plugin flow (Settings → Plugins), from a Git URL or a local path. The repository includes a Cursor manifest at [`.cursor-plugin/plugin.json`](.cursor-plugin/plugin.json); skills, agents, and references are shared with the Claude plugin. +**Cursor**: add this repository as a plugin (Settings → Plugins, from a Git URL or a local path). The repo includes a Cursor manifest at [`.cursor-plugin/plugin.json`](.cursor-plugin/plugin.json); skills, agents, references, and hook scripts are shared with the Claude plugin. See [docs/install.md](docs/install.md) for marketplace, local-development, update, and Cursor install details. ## Components -| Component | Status | Purpose | -|-----------|--------|---------| -| Skill `docs-editing` | shipped | Auto-invoked router: sends each prose task to the skill that owns it, and to the canonical rule in `references/`. | -| Skill `/technical-writing` | shipped | Author new documentation: picks exactly one document kind, reads the code before drafting, runs the commands it writes. | -| Skill `/copy-editing` | shipped | Tighten existing prose. Establishes the proofread / line-edit / structural contract first, then works large-to-small; claims pass runs first. | -| Skill `/humanize` | shipped | Remove AI tells from existing prose: signposting, staged contrasts, inflated significance, chatbot residue, decorative formatting. Restates without adding facts, keeps a human author's em dashes, and never judges authorship. | -| Skill `/marketing-copy` | shipped | Landing, feature, and announcement copy for technical audiences, with the anti-fabrication guardrails applied before drafting. | -| Skill `/seo-audit` | shipped | Technical and on-page audit of the **published** output: titles, descriptions, headings, canonicals, sitemap, redirects, orphans. | -| Skill `/ai-seo` | shipped | Citability by AI search: `llms.txt`, Markdown twins, validated JSON-LD, chunk-level self-containment. | -| Skill `/docs-lint-setup` | shipped | Scaffold `.vale.ini`, seed the vocabulary and add the `ai-tells` style; never overwrites an existing config unprompted. | -| Agent `prose-reviewer` | shipped | Report-only prose review for what linters cannot see: unsourced claims, doc-kind bleed, stale inventories, terminology drift. Ranked findings. | -| Agent `seo-auditor` | shipped | Report-only discoverability sweep over a docs tree or live site, with a mandatory coverage statement. | -| Session-start hook | shipped | Detects a docs/content workspace and prints one standards line plus the surface; dual-host. Silent in a repo with only a `README.md`. | -| Prose-lint hook | shipped | After each `.md` edit, reports `vale` alerts. Advisory (**never rewrites**) and opt-in: silent unless the repo carries its own `.vale.ini`. | -| References | shipped | The canonical rules, cited by every component: [claims and evidence](references/claims-and-evidence.md), [house style](references/style-guide.md), [document kinds](references/doc-types.md), [AI tells](references/ai-tells.md), [SEO checklist](references/seo-checklist.md), plus the reference `vale.ini`, its `vocab-accept.txt` seed and the `ai-tells` Vale style. | -| Cursor rule `docs-editing-context.mdc` | shipped | Markdown- and docs-scoped guidance mirroring the router for Cursor. | +| Component | Purpose | +|-----------|---------| +| Skill `docs-editing` | Auto-invoked router: sends each prose task to the skill that owns it, and to the canonical rule in `references/`. | +| Skill `/technical-writing` | Drafts new documentation in exactly one document kind. Reads the code before drafting and runs the commands it writes. | +| Skill `/copy-editing` | Tightens existing prose. Settles the proofread, line-edit, or structural contract first, then works from large to small, starting with the claims pass. | +| Skill `/humanize` | Removes AI tells from existing prose: signposting, staged contrasts, inflated significance, chatbot residue, decorative formatting. Restates without adding facts, keeps a human author's em dash where its passage has no other tell, and never judges authorship. | +| Skill `/marketing-copy` | Writes landing, feature, and announcement copy for technical readers, with the anti-fabrication guardrails applied before drafting. | +| Skill `/seo-audit` | Audits the **published** output, technical and on-page: titles, descriptions, headings, canonicals, sitemap, redirects, orphans. | +| Skill `/ai-seo` | Audits and improves citability by AI search: `llms.txt`, Markdown twins, validated JSON-LD, chunk-level self-containment. | +| Skill `/docs-lint-setup` | Scaffolds `.vale.ini`, seeds the vocabulary, and adds the `ai-tells` style. Never overwrites an existing config unprompted. | +| Agent `prose-reviewer` | Report-only review of what linters cannot see: unsourced claims, doc-kind bleed, stale inventories, terminology drift. Returns ranked findings. | +| Agent `seo-auditor` | Report-only discoverability sweep over a docs tree or live site, with a mandatory coverage statement. | +| Session-start hook | Detects a docs or content workspace and prints one standards line plus the skill and agent surface; dual-host. Stays silent in a repo with only a `README.md`. | +| Prose-lint hook | After each Markdown edit, reports `vale` alerts for that file; dual-host. Advisory (it **never rewrites** the file) and opt-in: silent unless the repo carries its own `.vale.ini` (or `_vale.ini`). | +| References | The canonical rules the skills, agents, and Cursor rule cite: [claims and evidence](references/claims-and-evidence.md), [house style](references/style-guide.md), [document kinds](references/doc-types.md), [AI tells](references/ai-tells.md), and the [SEO checklist](references/seo-checklist.md). | +| Lint config `references/vale.ini` | The reference Vale config that `/docs-lint-setup` scaffolds from, with its `vocab-accept.txt` vocabulary seed and the `ai-tells` Vale style. | +| Cursor rule `docs-editing-context.mdc` | Markdown- and docs-scoped guidance mirroring the router for Cursor. | + +Neither agent's tool grant includes `Write` or `Edit`, but both include `Bash` for read-only commands (Vale for `prose-reviewer`; builds, greps, and fetches for `seo-auditor`), so report-only is a contract their bodies keep rather than a sandbox that enforces it. + +The guidance draws on [Diátaxis](https://diataxis.fr) for document kinds, [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org) for changelogs, [Vale](https://vale.sh) with the `Google`, `write-good`, `alex`, and `proselint` style packages for prose style, the [llms.txt proposal](https://llmstxt.org) for AI citability, and Wikipedia's [Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) for AI tells. -## The rule that defines it - -> **A claim that cannot be traced to a source does not ship.** - -Generative copy tooling fails in one predictable way: asked to make a page more persuasive, it invents the persuasion (statistics, customer counts, testimonials, awards, urgency). Those are the conventional ingredients of landing-page copy, which is why they get fabricated. - -For a technical audience they also backfire. Developers, engineers, and clinicians read an unsourced number as evidence of unseriousness, so the growth-copy move that lifts conversion on a consumer page lowers trust here. Every skill in this plugin substitutes the **observable mechanism** instead: - -> ❌ "Cuts documentation review time by 40%." -> ✅ "Flags unsourced statistics, doc-kind bleed, and inventories that no longer match the tree." +## How it decides -The mechanism is specific and checkable, and it convinces this reader more than a number they assume was invented. Hedging is no escape: "up to", "designed to", and "teams report" preserve the violation. The full rule, including the never-invent list and the repair pattern, is [`references/claims-and-evidence.md`](references/claims-and-evidence.md). +**The repository being worked on outranks this plugin.** Before writing or editing, the `docs-editing` router (and, on Cursor, the rule) has the assistant read the target repo's `AGENTS.md` or `CLAUDE.md`, its style guide, its linter config, and neighbouring pages. Where those conflict with the plugin, the repo wins, and so does any ground-truth source it names for domain facts. -## How it decides +Below that, three principles apply in priority order: -One constraint comes first: **the repository being worked on outranks this plugin.** Every skill reads the target repo's `AGENTS.md`, style guide, and linter config first, and reports a conflict rather than silently overriding it, including any named ground-truth source for domain facts. +1. **Evidence before persuasion.** A claim that cannot be traced to a source does not ship, and this outranks every stylistic preference. Generative copy tooling fails in one predictable way: asked to make a page more persuasive, it invents the persuasion (statistics, customer counts, testimonials, awards, urgency). Developers, engineers, and clinicians read an unsourced number as evidence of unseriousness, so the growth-copy move that lifts conversion on a consumer page lowers trust here. The writing and editing skills state the observable mechanism instead: -Within that constraint, three principles apply in priority order: + > ❌ "Cuts documentation review time by 40%." + > ✅ "Flags unsourced statistics, doc-kind bleed, and inventories that no longer match the tree." -1. **Evidence before persuasion**: [the rule that defines it](#the-rule-that-defines-it). It outranks every stylistic preference. -2. **One document kind per file**: most bad documentation is a tutorial and a reference merged into one page. Decide the kind first ([Diátaxis](https://diataxis.fr)-based; see [`references/doc-types.md`](references/doc-types.md)), then write only that kind. -3. **Deterministic beats prose**: whatever `vale` enforces, run the tool rather than reasoning it out by hand. Markdown *structure* has no shipped enforcer; those conventions are applied by judgment. + Hedging is no repair: "up to", "designed to", and "teams report" keep the claim. The full rule, with the never-invent list, is [`references/claims-and-evidence.md`](references/claims-and-evidence.md). +2. **One document kind per file.** Most bad documentation is a tutorial and a reference merged into one page. `/technical-writing` picks the kind before drafting and writes only that kind; `/copy-editing` and `prose-reviewer` report a page that mixes two. The kinds follow [Diátaxis](https://diataxis.fr), per [`references/doc-types.md`](references/doc-types.md). +3. **Deterministic beats prose.** Where Vale enforces a rule, the writing and editing skills run it rather than reasoning the rule out by hand. Markdown *structure* has no shipped enforcer, so those conventions are a matter of judgment. -The components write **prose for people**: documentation, guides, references, page and marketing copy, changelogs, release notes, site metadata, `llms.txt`. Agent-instruction files address a model rather than a reader, which inverts three of the rules here: repetition becomes deliberate, hard constraints must stay hard, and rigid parallel structure becomes a feature. A prose editor tuned for human readers quietly degrades them, so that genre belongs to tooling built for it. +The components write **prose for people**: documentation, guides, references, page and marketing copy, changelogs, release notes, site metadata, `llms.txt`. Agent-instruction files stay out of scope because they address a model, not a reader, and the rules for human readers invert for them: repetition is deliberate, hard constraints must stay hard, rigid parallel structure is a feature, and spelling out the failure mode is the point. A prose editor tuned for human readers would quietly degrade them ([`references/doc-types.md` §3](references/doc-types.md#3-not-documentation-agent-instruction-files)). ## Development -No build step: the plugin is pure Markdown + JSON. Validate locally: +The plugin has no build step. Validate locally: ```bash ./scripts/validate.sh # manifests, parity, frontmatter, references, links, tool grants, doc sync claude plugin validate . # manifest + component structure ``` -Beyond the checks shared with the sibling Cadasto plugins, the validator enforces four invariants specific to this plugin: reference resolution, Markdown links and anchors, tool grants, and doc sync. The [Validation section of docs/testing.md](docs/testing.md#validation) defines each one and the drift it guards against. See [`AGENTS.md`](AGENTS.md) for contributor conventions. +Beyond the checks shared with the sibling Cadasto plugins, the validator enforces four invariants specific to this plugin: reference resolution, Markdown links and anchors, tool grants, and doc sync. The [Validation section of docs/testing.md](docs/testing.md#validation) defines each one and the drift it guards against. ## Documentation - [docs/install.md](docs/install.md): install on both hosts, and the optional linter toolchain - [docs/testing.md](docs/testing.md): validate and dogfood -- [docs/versioning.md](docs/versioning.md): SemVer and release steps +- [docs/versioning.md](docs/versioning.md): SemVer policy and release steps - [docs/authoring.md](docs/authoring.md): skill, agent, and rule authoring conventions +See [AGENTS.md](AGENTS.md) for contributor conventions. + ## License [MIT](LICENSE) diff --git a/docs/authoring.md b/docs/authoring.md index 829c684..f519c9a 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -17,13 +17,13 @@ This page is for contributors adding or changing a skill, agent, or Cursor rule ## The `description` (the trigger) -For skills the `description` is always-on metadata: keep it lean and third person: *what + scope*, then 3–5 representative triggers as **quoted phrases a user would actually type** ("write a README", "tighten this copy", "add llms.txt"), then a short **"Not for …"** anti-trigger disambiguating it from its neighbours. The worker skills sit close together, so the anti-trigger is what stops the wrong one loading: `technical-writing` vs `copy-editing` is *new* vs *existing*; `copy-editing` vs `humanize` is *any defect* vs *AI tells*; `seo-audit` vs `ai-seo` is *crawlers* vs *retrieval*; `marketing-copy` vs `technical-writing` is *persuasion* vs *documentation*. +For skills the `description` is always-on metadata, so keep it lean and in the third person. Give *what + scope*, then 3–5 representative triggers as **quoted phrases a user would actually type** ("write a README", "tighten this copy", "add llms.txt"), then a short **"Not for …"** anti-trigger that tells it apart from its neighbours. The worker skills sit close together, so the anti-trigger is what stops the wrong one loading: `technical-writing` vs `copy-editing` is *new* vs *existing*; `copy-editing` vs `humanize` is *any defect* vs *AI tells*; `seo-audit` vs `ai-seo` is *crawlers* vs *retrieval*; `marketing-copy` vs `technical-writing` is *persuasion* vs *documentation*. **YAML gotcha:** a `description` value with an unquoted `: ` (colon-space) makes a real YAML parser read it as a nested mapping, so the component loads with *empty* metadata, every field silently dropped. `claude plugin validate` catches this, and `scripts/validate.py` guards against it too. Quote the value, or use a `>` block scalar (as the agents do). ## Body -- **Cite the references; do not re-derive them.** The single source of truth for the rules is `references/`: `claims-and-evidence.md` (the hard rule), `style-guide.md`, `doc-types.md`, `seo-checklist.md`. A skill body states *its procedure* and points at the canonical reference for the rules. This keeps skills lean and the rules in one place: when a rule changes, one file changes. +- **Cite the references; do not re-derive them.** The single source of truth for the rules is `references/`: `claims-and-evidence.md` (the hard rule), `style-guide.md`, `doc-types.md`, `ai-tells.md`, and `seo-checklist.md`. A skill body states *its procedure* and points at the canonical reference for the rules. This keeps skills lean and the rules in one place: when a rule changes, one file changes. - **`references/` is plugin-root-relative.** A bare `references/x.md` inside `skills//SKILL.md` is two levels off, so every component carries the one-line resolution note (`${CLAUDE_PLUGIN_ROOT}/references/…`, `../../references/…`, or Glob). The validator checks that every cited reference exists; it cannot check that a reader resolves the path, which is why the note is mandatory. - **The repo being worked on outranks this plugin.** Every skill instructs reading the target repo's `AGENTS.md` / style guide / linter config first, and treats a conflict as the repo's win, reported rather than silently overridden. - **Deterministic beats prose.** Where `vale` enforces a rule, the skill runs the tool and reports its real output. Markdown structure has no shipped enforcer; do not write guidance implying one. A skill must never claim a clean lint it did not run. diff --git a/docs/install.md b/docs/install.md index 3f825fe..b08add2 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,6 +1,6 @@ # Installing the Docs Editing Plugin -This page is for anyone installing, updating, or loading a working copy of the plugin on [Claude Code](https://docs.claude.com/en/docs/claude-code/plugins) (`.claude-plugin/`) or [Cursor](https://cursor.com/docs/plugins) (`.cursor-plugin/`), and for setting up the optional Vale toolchain. Skill, agent, and reference content is shared; only the manifest and hook layer differ. The plugin is pure Markdown + JSON, with no build step and **no MCP server** to wire up. +This page is for anyone installing, updating, or loading a working copy of the plugin on [Claude Code](https://docs.claude.com/en/docs/claude-code/plugins) (`.claude-plugin/`) or [Cursor](https://cursor.com/docs/plugins) (`.cursor-plugin/`), and for setting up the optional Vale toolchain. Both hosts share the skill, agent, and reference content; only the manifests, the hook configs, and the Cursor-only rule in `rules/` differ. The plugin is pure Markdown + JSON, with no build step and **no MCP server** to wire up. ## Claude Code @@ -19,11 +19,11 @@ The marketplace name is `cadasto`, so the plugin is addressed as `docs-editing@c claude --plugin-dir /path/to/docs-editing-plugin ``` -`--plugin-dir` loads the plugin from disk for **that session only**; it does not persist, which makes it the right tool for dogfooding an unreleased working copy. It is repeatable (`--plugin-dir A --plugin-dir B`) and also accepts a `.zip`. +`--plugin-dir` loads the plugin from disk for **that session only**, which makes it the right tool for dogfooding an unreleased working copy. It is repeatable (`--plugin-dir A --plugin-dir B`) and also accepts a `.zip`. -**`claude plugin add` does not exist.** `claude plugin install` resolves names from a configured marketplace, not filesystem paths, and `claude plugin marketplace add ` expects a marketplace manifest (`.claude-plugin/marketplace.json`), which a single-plugin repository like this one does not have. For a persistent install, go through the marketplace above. +**`claude plugin add` does not exist.** `claude plugin install` resolves names from a configured marketplace, not filesystem paths, and `claude plugin marketplace add ` expects a marketplace manifest (`.claude-plugin/marketplace.json`), which a single-plugin repository like this one does not have. For a persistent install, use the marketplace. -Combine it with a subcommand to inspect a working copy without installing: +Combine `--plugin-dir` with a subcommand to inspect a working copy without installing it: ```bash claude --plugin-dir /path/to/docs-editing-plugin plugin details docs-editing @@ -41,13 +41,13 @@ claude plugin details docs-editing # component inventory + projected token /plugin update docs-editing ``` -A session restart is required for an update to take effect. +Restart the session for an update to take effect. ## Cursor Add this repository as a plugin (Cursor **Settings → Plugins**, via Git URL or local path). The repo root contains `.cursor-plugin/plugin.json`, which declares the `skills`, `agents`, `rules`, and `hooks` paths. After changing content locally, reload or reinstall the plugin so Cursor picks it up. -> The Cursor hook wiring targets the `sessionStart` and `afterFileEdit` events. If your Cursor version exposes a different post-edit event or payload shape, adjust `hooks/cursor-hooks.json` and the path-extraction in `hooks/prose-lint-on-save.sh` accordingly. +> The Cursor hook wiring targets the `sessionStart` and `afterFileEdit` events. If your Cursor version exposes a different post-edit event or payload shape, adjust `hooks/cursor-hooks.json` and the path extraction in `hooks/prose-lint-on-save.sh` to match. ## Host toolchain (optional but recommended) @@ -69,7 +69,7 @@ vale --minAlertLevel=error . # errors only -- the triage baseline Vale exits `0` clean, `1` on findings, `2` on a config error. Prefer the [release binaries](https://github.com/vale-cli/vale/releases); `go install` currently fails to build. -Without Vale the skills still apply the standards by judgment, and the save hook stays silent. +Without Vale the skills still apply the standards by judgment, and the prose-lint hook stays silent. `ai-seo` and `seo-audit` audit the **published** output, so they use `WebFetch` (or `curl`) against a deployed URL, or read a built output directory. Neither needs a network connection to give source-level findings, but both label such findings as unverified against the published output. @@ -80,4 +80,4 @@ Two host-agnostic hooks ship (Claude `hooks/hooks.json`, Cursor `hooks/cursor-ho - **`session-start.sh`**: on session start, detects a docs/content workspace (a generated-site config, a prose-linter config, or a `docs/`, `pages/`, or `content/` tree containing Markdown) and prints one context line plus the available skill and agent surface. A bare `README.md` deliberately does not count, or the hook would fire in every repository. - **`prose-lint-on-save.sh`**: after an edit to a `.md`, `.mdx`, or `.markdown` file (Claude `PostToolUse` on `Write`/`Edit`; Cursor `afterFileEdit`), runs `vale` on that one file and prints the alerts. - It is **advisory and never rewrites the file**: prose is not mechanically formattable the way source code is, so an auto-fixing save hook would silently edit an author's voice. It is also **opt-in**: it runs only when the repository carries its own `.vale.ini`, so it stays silent in a repo that has not asked for prose linting. Output is capped so it cannot flood the context window. It always exits 0 and can never block an edit. + The hook is **advisory and never rewrites the file**: prose cannot be formatted mechanically the way source code can, so an auto-fixing save hook would silently edit an author's voice. It is also **opt-in**, running only when the repository carries its own `.vale.ini` (or `_vale.ini`), so a repo that has not asked for prose linting sees nothing. Its output is capped so it cannot flood the context window, and it always exits 0, so it never blocks an edit. diff --git a/docs/testing.md b/docs/testing.md index fffc366..e35be89 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -4,10 +4,10 @@ This page is for contributors checking a change before a pull request or a relea ## Validation -- **Manifest / component validation**: `./scripts/validate.sh` (also run by CI on every PR). The wrapper runs `scripts/validate.py`; if Python 3 is not installed it prints a warning and skips (exit 0) rather than failing; install `python3` for the full local check, or rely on `claude plugin validate .` and CI. CI pins Python so the deep check always runs there. +- **Manifest / component validation**: `./scripts/validate.sh`, a wrapper around `scripts/validate.py`. Without Python 3 the wrapper prints a warning and exits 0 instead of failing; install `python3` for the full local check, or rely on `claude plugin validate .` and CI. CI installs Python 3 and runs `scripts/validate.py` directly on every pull request and push to `main`, so the full check always runs there. - **Official validator**, `claude plugin validate .`: checks the manifest and component structure (no extra dependencies). - **Structural review**: run the `plugin-dev:plugin-validator` agent after creating or modifying components. -- **Skill quality review**: run the `plugin-dev:skill-reviewer` agent, covering description-triggering quality, progressive disclosure, content structure. +- **Skill quality review**: run the `plugin-dev:skill-reviewer` agent, covering how well each description triggers, progressive disclosure, and content structure. - **Token cost**: `claude plugin details docs-editing` shows the inventory and projected token cost. Only the frontmatter `description` of each skill is always-on; keep those lean. ### What `scripts/validate.py` checks @@ -19,12 +19,12 @@ Generic, shared with the sibling Cadasto plugins: - Every component path a manifest declares exists inside the plugin directory. - Kebab-case names for skills, agents, and rules. - Hook-config JSON validity, **and** that every hook script it names exists and is executable. -- Skill / agent / rule frontmatter: required keys, `name` matching the directory or filename stem, and the unquoted-`': '` YAML trap that silently drops all metadata. **Agents must declare `tools:`, never `allowed-tools:`**; flagged as an error. +- Skill / agent / rule frontmatter: required keys, `name` matching the directory or filename stem, and the unquoted-`': '` YAML trap that silently drops all metadata. **An agent must declare `tools:`; a missing `tools:` key or any `allowed-tools:` key is an error.** -Four invariants specific to this plugin, each guarding a drift class this repo is genuinely exposed to: +Four invariants specific to this plugin, each guarding a drift class this repo is exposed to: - **Reference resolution**: every `references/` cited by a skill or agent body exists, and the reference files' own relative links resolve. The bundled `references/` sit at the **plugin root** while a citing skill sits two levels down, so a stale path fails silently at load time and the component improvises rules instead of grounding in them. This is the single most damaging failure mode for a plugin whose value is its cited rules. -- **Markdown links and anchors**: every *relative* link in every `.md`/`.mdc` file resolves, and every `#anchor` it targets matches a heading in the destination (GitHub slug rules, including the `-1` suffix for duplicate headings). Link syntax inside code fences and inline code spans is skipped, because there it is illustrative rather than a link. External links are deliberately **not** fetched; that needs network and would make the validator flaky; see [versioning.md](versioning.md#coupling-to-external-tooling) for the external drift that stays unmonitored. Internal link rot is exactly the defect this plugin tells other repositories to fix, so it is checked here rather than trusted. +- **Markdown links and anchors**: every *relative* link in every `.md`/`.mdc` file resolves, and every `#anchor` it targets matches a heading in the destination (GitHub slug rules, including the `-1` suffix for duplicate headings). Link syntax inside code fences and inline code spans is skipped, because there it is illustrative rather than a link. External links are deliberately **not** fetched, because that needs a network and would make the validator flaky; [versioning.md](versioning.md#coupling-to-external-tooling) covers the external drift that stays unmonitored. Internal link rot is exactly the defect this plugin tells other repositories to fix, so it is checked here rather than trusted. - **Tool grants**: two advice-vs-capability checks, both added after this repo shipped the defects they catch. A component whose body prescribes a shell command (a shell-tagged fence, or an inline `vale`/`curl` invocation) must declare `Bash`; otherwise the instruction cannot be followed without a permission prompt its sibling components avoid. And an agent must not declare `Write`/`Edit`, nor describe itself as "read-only" while holding a write-capable tool; `Bash` counts, since `sed -i` and `>` write. Agents here are **report-only**: a contract their bodies keep, not a sandbox that keeps it for them, and the docs must not claim otherwise. - **Doc sync**: every worker skill and every agent is named both in the `docs-editing` router's body and in `hooks/session-start.sh`. A component that exists but is not routed to is unreachable in practice, and the session-start line is what tells a user it exists.