Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"./skills/meta/agent-readiness",
"./skills/reference/rhdh-context",
"./skills/meta/ask-rhdh",
"./skills/meta/clean-prose",
"./skills/reference/prose-editing",
"./skills/meta/setup-rhdh-skills",
"./skills/reference/mutation-gate",
"./skills/meta/skill-authoring"
Expand All @@ -27,6 +29,7 @@
"./skills/release/rhdh-overlay-cve-export",
"./skills/release/rhdh-platform-lifecycle",
"./skills/release/rhdh-release-announce",
"./skills/reference/prose-editing",
"./skills/release/rhdh-release-schedule",
"./skills/release/rhdh-release-status",
"./skills/release/rhdh-release-teams",
Expand Down Expand Up @@ -66,6 +69,7 @@
"./skills/plugins/rhdh-plugin-wiring",
"./skills/plugins/rhdh-pr-create",
"./skills/plugins/rhdh-pr-review",
"./skills/reference/prose-editing",
"./skills/plugins/rhdh-test-placement"
]
},
Expand Down
1 change: 1 addition & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"MD024": {
"siblings_only": true
},
"MD028": false,
"MD029": false,
"MD036": false,
"MD040": false,
Expand Down
21 changes: 15 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,19 @@ utterances is several skills. Split by verb, never by noun, and weight the split
by what a misroute costs — merge where a misroute produces a wrong write, split
where it produces an obvious wrong answer. See ADR-0005.

Only `ask-rhdh` and `setup-rhdh-skills` are human-invoked. They carry
`disable-model-invocation: true` in `SKILL.md` and
`policy.allow_implicit_invocation: false` in `agents/openai.yaml`. Every other
Human invocation is a class, not a roster. A human-invoked skill is an entry
point a person types by name, and the router never reaches it. Every member
carries `disable-model-invocation: true` in `SKILL.md` and
`policy.allow_implicit_invocation: false` in `agents/openai.yaml`. Admit a new
one only when it holds no substance of its own and delegates to exactly one
model-invoked skill, the way `clean-prose` delegates to `prose-editing`;
`ask-rhdh` and `setup-rhdh-skills` are the other members today. Every other
promoted skill is model-invoked and omits both flags. Every promoted skill has
an `agents/openai.yaml` interface entry.

The complete pack also requires three external skills. Creation and interview
flows use `/grilling`; PR-review prose uses `/humanizer`; `/handoff` carries
context into a later session, which is why no artifact store does.
The complete pack also requires two external skills. Creation and interview
flows use `/grilling`; `/handoff` carries context into a later session, which is
why no artifact store does.

Keep drafts and retired skills outside the promoted discovery root:

Expand All @@ -86,6 +90,11 @@ Do not add them to promoted manifests or catalogs.
artifacts remain credential-free. Setup owns login and never creates a
parallel credential store.
- `/rhdh-context` owns shared repository and version context.
- `/prose-editing` owns the prose pass. A PR-review draft and a freeze
announcement both go through it before anyone sees them: `/rhdh-pr-review`
invokes it in the flavored register, `/rhdh-release-announce` in the voiced
one. The caller names the register, because the caller knows what kind of
document it wrote.
- Skills pass context by invoking each other by name. There is no artifact
envelope and no artifact store. When the user needs context to survive into a
later session, tell them to run `/handoff`.
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ uv run pytest
```

For end-to-end skill use, install the complete pack documented in
[README.md](README.md), including `/grilling` and `/humanizer`.
[README.md](README.md), including `/grilling` and `/handoff`.

## Choose the owning module

Expand Down Expand Up @@ -146,8 +146,8 @@ skill aliases and a mixed old/new catalog are intentionally excluded.

After the breaking branch is merged and tagged, a maintainer signs in at
`https://skills.sh/packs/create`, creates the `RHDH complete` pack from the
tagged repository plus `grilling` and `humanizer`, and records the resulting
tagged repository plus `grilling` and `handoff`, and records the resulting
`https://skills.sh/p/<pack-id>` URL in the setup catalog. Packs are unlisted,
not access-controlled, so never include credentials or private files. Until
that URL exists, `/setup-rhdh-skills` emits the equivalent three-source install
that URL exists, `/setup-rhdh-skills` emits the equivalent two-source install
plan.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ behind a small set of task-oriented interfaces.

## Install

Install the pack and the three external skills it depends on. Each command opens
Install the pack and the two external skills it depends on. Each command opens
the skills wizard, which asks where to put them:

```bash
npx skills add redhat-developer/rhdh-skills --global
npx skills add mattpocock/skills --global
npx skills add blader/humanizer --global
```

Restart your agent client so it discovers them.
Expand Down Expand Up @@ -47,9 +46,9 @@ one. It performs no work itself.
`skills/meta/setup-rhdh-skills/assets/catalog.json` is the machine-readable roster
and the single source of truth for membership. This file does not restate it.

Two skills are human-invoked and never selected automatically: `/ask-rhdh` and
`/setup-rhdh-skills`. The other 39 are model-invoked, and can also be called by
name.
Three skills are human-invoked and never selected automatically: `/ask-rhdh`,
`/setup-rhdh-skills`, and `/clean-prose`. The other 40 are model-invoked, and can
also be called by name.

Skills are grouped into six folders:

Expand All @@ -59,8 +58,8 @@ Skills are grouped into six folders:
| `plugins/` | Authoring, wiring, exporting, and fixing Backstage dynamic plugins; the overlays repository; local RHDH; opening and reviewing pull requests; midstream propagation. |
| `ci/` | Prow job configuration and nightly triggers, Konflux and Tekton task updates, base images, and Yarn bumps. |
| `release/` | Release status and readiness, milestone schedules, freeze announcements, teams, test-plan review, platform lifecycle, and the plugin CVE export. |
| `reference/` | The reusable layer other skills invoke by name: repository and version context, the forge read seam, the write gate, and the Jira and Backstage reference material. |
| `meta/` | The two human-invoked entry points, plus skill authoring and repository agent-readiness. |
| `reference/` | The reusable layer other skills invoke by name: repository and version context, the forge read seam, the write gate, the prose pass, and the Jira and Backstage reference material. |
| `meta/` | The three human-invoked entry points, plus skill authoring and repository agent-readiness. |

## How skills compose

Expand All @@ -79,12 +78,15 @@ there is no shared runtime package, provided anything it invokes is also present
skill it did not install from one you wrote and kept, so removing anything else
is yours to do.

Three skills come from outside this repository and are required rather than
Two skills come from outside this repository and are required rather than
optional. `/grilling` supplies the interview discipline that skill authoring and
Jira creation depend on, so those flows stop rather than guess. `/humanizer` runs
before any PR-review prose is shown or posted, so drafts do not go out reading
like a machine wrote them. `/handoff` is what carries context into a later
session, which is why this pack ships no artifact store of its own.
Jira creation depend on, so those flows stop rather than guess. `/handoff` is
what carries context into a later session, which is why this pack ships no
artifact store of its own.

Prose that leaves the pack goes through `/prose-editing` first, so a review or a
freeze announcement does not go out reading like a machine wrote it. Run
`/clean-prose` to put your own draft through the same pass.

Every external write goes through the write gate. The skill states each operation
with its target, exact command, preview, and what happens on failure; you approve
Expand Down
100 changes: 100 additions & 0 deletions docs/adr/0010-prose-editing-registers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# One prose skill, three registers

**Status:** Accepted.

## Context

Two skills carried `/humanizer` (blader/humanizer, MIT, its catalogue derived
from Wikipedia's CC BY-SA "Signs of AI writing") as a hard prerequisite:
`/rhdh-pr-review` and `/rhdh-release-announce`, both instructing the agent to
never show pre-humanizer prose. A separate proposal added a Simplified Technical
English skill with a bundled linter. The two looked like complements — one
removes the machine register, the other tightens technical writing — and were
scoped to sit beside each other.

Measuring them says otherwise. A sample containing seventeen distinct AI writing
tells scored 5.93 against the linter's 2.5 bar, so it failed. But every flagged
category was incidental — four contractions, passive voice, a nominalization,
one long paragraph — and **not one of the seventeen tells was detected**. An
agent told to repair every reported category fixes the contractions, re-lints
under the bar, and returns prose that is still obviously machine-written with a
passing score attached. That is worse than no score, because it certifies the
failure.

The bar has a second problem: it rejects prose this repository already treats as
good. `README.md` scores 2.68, `skill-authoring/SKILL.md` 3.15, and the proposed
skill's own `SKILL.md` 4.85 against the 2.5 bar it was proposing.

The two skills also claimed overlapping utterances. Both answer "clean up this
PR body" and "tighten this announcement", which
[ADR-0005](0005-one-skill-per-trigger-phrase.md) forbids.

## Decision

Merge them into one model-invoked reference skill, `/prose-editing`, with a
human-invoked wrapper, `/clean-prose`. The external dependency is removed.

**One skill, because the split test is the verb.** "Remove the AI tells" and
"tighten this runbook" are the same verb applied to different document types,
and a document type is a noun. Splitting by noun is what ADR-0005 rejects, and
for its usual reason: the user often does not know which treatment they want, so
choosing it is the skill's job. ADR-0005 also weights the split by the cost of a
misroute, and a misroute here produces a wrong *write* — an announcement
flattened into aircraft-manual English. That is the case that merges.

**The contradiction is about compression, not tells.** STE strips voice on
purpose; humanizer's personality guidance exists to keep it. That reads as
irreconcilable until you separate what the two systems actually score. They do
not disagree about tells; they disagree about compression. Three layers fall
out: mechanical tells, scored in every register; compression, scored only
where prose should be flat; voice, scored only where prose is allowed one. Those
give three registers — `strict`, `flavored`, `voiced` — inferred from document
type, plus a read-only `review` route. A caller that knows names the register:
`/rhdh-pr-review` uses flavored, `/rhdh-release-announce` uses voiced.

**The score is a delta, not a gate.** Violation density is a function of
document type, so an absolute bar across arbitrary prose is a promise the metric
cannot keep — the README and `skill-authoring` numbers are that promise breaking
on curated text. The skill reports before and after and leaves the judgement
with the reader. The fixed bar survives only as a `--fail-over N` knob a human
points at their own corpus in CI, where the text is uniform enough for one
number to mean something.

**The capability comes in-pack.** Two skills hard-failing on a third-party
repository is a live failure mode on the path of every PR review, and owning the
capability removes it. It is also the extraction
[ADR-0006](0006-duplication-by-layer.md) asks for — a pattern catalogue is
prompt material, so it gets one home behind a named interface rather than a copy
in each caller, while the bundled linter is code and stays self-contained.
Owning it removes a licensing hazard too: reproducing humanizer's prose would
pull CC BY-SA text into an Apache-2.0 repository. The taxonomy is taken and
every rule restated independently, with a NOTICE at
`skills/reference/prose-editing/scripts/NOTICE` carrying the MIT terms of both
upstream projects.

**The wrapper is safe because the router cannot see it.**
[ADR-0008](0008-skill-naming-and-namespace-isolation.md) establishes that
isolation is the description's job, and two skills about editing prose would
collide by description whatever they were named.
`disable-model-invocation: true` takes `/clean-prose` out of the routing set
entirely, so it cannot compete with the reference skill it delegates to. That is
a structural guarantee rather than a convention, which is why the human-invoked
rule is stated as a class of skill rather than a roster of names. Neither skill
takes the `rhdh-` prefix: editing prose is not about Red Hat Developer Hub.

## Consequences

- One skill answers both utterances. `/rhdh-pr-review` and
`/rhdh-release-announce` name a register instead of declaring a prerequisite,
and no third-party repository sits on the path of a review.
- The pack maintains a pattern catalogue it previously rented, on a
taxonomy-only footing: whoever adds a pattern restates it rather than quoting
a source. Upstream improvements stop arriving for free.
- Three registers are more surface than two modes, and register inference is a
new failure mode: a caller that names none gets the register the skill guesses.
A wrong guess is a wrong write — the same cost that argued for merging.
- The reported score no longer answers "is this good enough" by itself. That
question moves to a human, reading the delta or setting `--fail-over N`
against a corpus they own.
- The human-invoked rule in `AGENTS.md` becomes a property of a class of skill
rather than a list of two names, so a future wrapper needs no amendment.
Loading
Loading