From 1bdf754fb342d57d83a07f7e9e82581dd2c80a47 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:14:04 -0400 Subject: [PATCH 01/10] docs(claude-ops): record the machine-profile rulings Refs: #4666 Co-Authored-By: Claude Opus 5.5 --- ...e-machine-profile-as-a-claude-ops-skill.md | 13 ++- docs/out-of-scope/machine-profile.md | 86 ++++--------------- docs/specs/machine-profile-design.md | 43 ++++------ 3 files changed, 44 insertions(+), 98 deletions(-) diff --git a/docs/adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md b/docs/adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md index f9ccd6d570..1f788fc50b 100644 --- a/docs/adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md +++ b/docs/adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md @@ -1,6 +1,6 @@ # Place the machine profile as a claude-ops skill -- Status: accepted for the placement only +- Status: accepted - Date: 2026-09-29 ## Context @@ -38,12 +38,11 @@ Place the profile as a skill in `claude-ops`, not as a new plugin. ## Status scope -Accepted for the placement only. The invocation-mode change (class (ii) and the hidden `setup` -skills) and any change to the setup contract stay deferred to the owner's later decision on the -design document. This record does not authorize the skill, its scripts, or a version bump. +Accepted. The skill, its scripts, its tests and the `claude-ops` version bump are authorized. The +invocation-mode change (class (ii) and the hidden `setup` skills) and any change to the setup +contract are not part of this decision. ## Consequences -The skill's directory is under `plugins/claude-ops/skills/`. Whether its scope is too broad for -`claude-ops` is the owner's call on the design document; if the owner chooses a new plugin, this -record is superseded. +The skill's directory is under `plugins/claude-ops/skills/`. A move to a new plugin would +supersede this record. diff --git a/docs/out-of-scope/machine-profile.md b/docs/out-of-scope/machine-profile.md index e0b4bb1ab2..2961f2a3b4 100644 --- a/docs/out-of-scope/machine-profile.md +++ b/docs/out-of-scope/machine-profile.md @@ -1,80 +1,32 @@ # Re-runnable machine profile for setup skills Record for -[#4666](https://github.com/melodic-software/claude-code-plugins/issues/4666), -a proposed host-fact store that would drive every plugin `setup` skill. - -Status: unratified agent proposal. The placement is accepted under -[ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md); the owner has not ruled -on whether to build it or on any setup-contract change, and #4666 is open for that decision. Until -then it is not a settled rejection. +[#4666](https://github.com/melodic-software/claude-code-plugins/issues/4666). ## Decision -**Superseded in part.** The design is now -[machine-profile-design](../specs/machine-profile-design.md) and the placement is -[ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md): a skill in -`claude-ops`. Building the skill and any setup-contract or invocation-mode change stay -undecided until the owner rules on that design. Until then, no `machine-profile` skill -exists, no new plugin is added, and the rest of this record stands. - -- **Option 1 (declined):** orchestrate by instruction. The profile would emit - `/:setup check` lines for the operator to type. That respects class - (ii) and is unpaid operator cost, not a skill to ship. -- **Option 2 (declined):** split `check` from `apply` so `check` is - model-invocable. The per-plugin form shipped in `actionlint`, `biome-format`, - `context7`, `go-format` and `markdown-format` (a separate model-invocable `check` - skill beside the manual `setup`) with no invocation-mode amendment; the class list in - `docs/conventions/invocation-mode/README.md` is still three. Whether to keep that - per-plugin split is an open owner question, - [#4240](https://github.com/melodic-software/claude-code-plugins/issues/4240) question 2. -- **Option 3 (declined):** relax `disable-model-invocation` on `check` only. - Same effect as option 2 with less structure. +The design is ratified: [machine-profile-design](../specs/machine-profile-design.md), placed as a +`claude-ops` skill by +[ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md). The skill is built as +`claude-ops` `machine-profile`. Only the following stays rejected or held: -**Claim (original park, before the design document):** a re-runnable machine profile that discovers host facts once and -drives the fleet's setup skills has no model-invocable path to them: all 58 -plugin `setup` skills are `disable-model-invocation: true`, which -`scripts/validate-plugin-contracts.mjs` requires. The model-invocable host -checks are `actionlint:check`, `biome-format:check`, `context7:check`, -`go-format:check` and `markdown-format:check` (one per plugin) and -`claude-ops:prerequisites`, a read-only report over the `prerequisites.json` -that 7 plugins declare. Host discovery stays inside each plugin's `setup`. If the idea returns, it is a `claude-ops` skill that feeds -`machine-health`'s declared-configuration drift check, never a second -host-fact store. -**Basis:** origin/main: 58 plugin-level `plugins/*/skills/setup/SKILL.md` -files, all `disable-model-invocation: true`, required at -`scripts/validate-plugin-contracts.mjs:189-190`. The `check` skill of each of -those five plugins and `plugins/claude-ops/skills/prerequisites/SKILL.md` -set `disable-model-invocation: false`. `docs/conventions/invocation-mode/README.md` -still lists three classes, class (ii) among them, and the invocation-reach -invariant (a `true` skill cannot be invoked by any other skill). No -`machine-profile` skill or plugin under `plugins/`. `machine-health` already -owns a `config` category for declared-configuration drift. -**As of:** 2026-09-29. -**Recheck:** a setup skill drops `disable-model-invocation: true` -(`git grep -L 'disable-model-invocation: true' -- 'plugins/*/skills/setup/SKILL.md'` -lists a file; it lists none today), or a maintainer funds a `claude-ops` skill -whose only job is a read-only host-fact document that `machine-health` -consumes. +- **Setup contract change (declined):** no setup skill is changed and + `validate-plugin-contracts.mjs` is untouched. +- **Invocation-mode class (ii) change (held):** the setup skills stay + `disable-model-invocation: true`. Splitting `check` from `apply`, relaxing the flag on `check`, + or adding a class would each be a fleet contract change across every `setup` skill. The profile + relies on reproduction and relay instead. +- **Orchestration by instruction (declined):** the profile does not emit `/:setup check` + lines for the operator to type. ## Rationale -- Naive orchestration is impossible today: every setup skill is model-hidden. -- Option 3 changes the contract `validate-plugin-contracts.mjs` enforces on all - 58 setup skills. Option 2 adds a `check` skill to each setup plugin that - lacks one. Neither is a claude-ops slice. -- A parallel host-fact document would compete with `machine-health` instead of - feeding it. -- Per-plugin setup already owns prerequisite logic and versions with the - plugin. Absorbing that into one driver is the gotcha the issue named. +- Every setup skill is model-hidden, so the profile cannot drive them directly. +- Changing class (ii) is a fleet contract change, not a `claude-ops` slice. +- Per-plugin setup owns prerequisite logic and versions with the plugin; the profile reads host + facts and does not absorb that logic. ## Revisit when -- a `setup` skill becomes model-invocable (the Recheck condition above), or -- the owner rules on the check/setup split in #4240 (question 2), or -- an operator go names a read-only host-fact document with no setup-skill - orchestration. - -## Prior requests - -- #4666 (2026-09-28): wayfind design item; parked here. Coordinated with #4240. +The built profile shows a check that the existing wrappers and reproduction cannot cover. The +class (ii) decision is tracked with #4240. diff --git a/docs/specs/machine-profile-design.md b/docs/specs/machine-profile-design.md index 86d07fb3ef..7556f2bb42 100644 --- a/docs/specs/machine-profile-design.md +++ b/docs/specs/machine-profile-design.md @@ -3,7 +3,8 @@ Design for a re-runnable machine profile that discovers host facts once, stores them, and hands each plugin's `setup` the answers. Tracked by [#4666](https://github.com/melodic-software/claude-code-plugins/issues/4666). This document -records design only: it changes no setup contract, no invocation-mode class, and no plugin. +records the design and its rulings. The build adds a `claude-ops` skill and changes no setup +contract and no invocation-mode class. ## Contents @@ -15,9 +16,9 @@ records design only: it changes no setup contract, no invocation-mode class, and - [Manual-change policy](#manual-change-policy) - [Reuse and machine-health](#reuse-and-machine-health) - [Placement](#placement) -- [Out of scope until the later decision](#out-of-scope-until-the-later-decision) +- [Out of scope](#out-of-scope) - [Acceptance criteria left for the build](#acceptance-criteria-left-for-the-build) -- [Open questions](#open-questions) +- [Rulings](#rulings) - [Verification record](#verification-record) ## Problem @@ -236,20 +237,18 @@ profile's `diff` is the only consumer. **Recommendation: a skill in `claude-ops`, not a new plugin.** **Basis:** `claude-ops` already owns fleet state and ships `prerequisites` and `inventory`, the two skills the profile reads; a new plugin would add a third owner of host facts beside -`machine-health`. Judgment on the remaining half: whether the skill's scope is too broad for -`claude-ops` stays with the owner when ruling on this document. The decision is recorded in +`machine-health`. The owner ratified the placement. The decision is recorded in [ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md). -## Out of scope until the later decision +## Out of scope -Held for the owner's later ruling on this document: +Not part of the build: - Any change to the setup contract, and any change to `validate-plugin-contracts.mjs`. - Amending invocation-mode class (ii) or adding a class, and any change to a `setup` skill's `disable-model-invocation` value. - Adding a model-invocable `check` skill for a plugin that lacks one. -- Version bumps and CHANGELOG entries for any touched plugin. -- The skill itself, its scripts, and its tests. +- Version bumps and CHANGELOG entries for any plugin other than `claude-ops`. ## Acceptance criteria left for the build @@ -268,21 +267,17 @@ tree under a scratch `HOME` and no real-host specifics: `npm view ctx7 version` writes `.npm/_logs` and an update-notifier marker under `HOME`. Test: hash both trees before and after. `apply` writes nothing without an explicit confirm. -## Open questions - -Each is for the later decision on this document. Placement is settled by -[ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md) and is not open here. - -1. **Class (ii).** Amend class (ii), add a class, or leave the setup skills hidden and rely on - reproduction. Recommendation: leave them hidden until the profile is built and shows a check the - wrappers and reproduction cannot cover. Unblocks: whether the fleet contract change happens at - all. -2. **Keying deviation.** Ratify a non-project-keyed machine section under plugin-data-report-keying. - Recommendation: ratify, with per-domain sections keyed by tree. Unblocks: the store's path scheme. -3. **The machine-health feed.** Whether machine-health ships a `config` check that reads the - profile, or the profile's `diff` stays the only consumer. Recommendation: ship the check only - once the profile exists and runs on an OS whose machine-health checks are implemented. Unblocks: the handoff - contract. +## Rulings + +Placement is settled by +[ADR 0041](../adr/0041-place-the-machine-profile-as-a-claude-ops-skill.md). + +1. **Class (ii).** The setup skills stay hidden and class (ii) is unchanged. The profile relies on + reproduction and relay. +2. **Keying deviation.** A non-project-keyed machine section is ratified under + plugin-data-report-keying, with per-domain sections keyed by tree. +3. **The machine-health feed.** The machine-health `config` check is deferred until the profile + exists and runs on an OS whose machine-health checks are implemented. ## Verification record From ea5df9298aa1d234aaf9a0b9ce79af411497ca19 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:24:08 -0400 Subject: [PATCH 02/10] feat(claude-ops): add the machine-profile skill Discovers host facts and per-tree identity domains read-only, validates and stores them behind a confirm, diffs the stored document with the host, and prints the values to hand to each setup without writing anything itself. Refs: #4666 Co-Authored-By: Claude Sonnet 5.5 --- .../skills/machine-profile/SKILL.md | 67 +++ .../skills/machine-profile/evals/evals.json | 57 +++ .../skills/machine-profile/scripts/profile.sh | 385 ++++++++++++++++++ .../machine-profile/scripts/profile.test.sh | 207 ++++++++++ .../claude-ops/skills/prerequisites/SKILL.md | 1 + 5 files changed, 717 insertions(+) create mode 100644 plugins/claude-ops/skills/machine-profile/SKILL.md create mode 100644 plugins/claude-ops/skills/machine-profile/evals/evals.json create mode 100755 plugins/claude-ops/skills/machine-profile/scripts/profile.sh create mode 100755 plugins/claude-ops/skills/machine-profile/scripts/profile.test.sh diff --git a/plugins/claude-ops/skills/machine-profile/SKILL.md b/plugins/claude-ops/skills/machine-profile/SKILL.md new file mode 100644 index 0000000000..02be9d6120 --- /dev/null +++ b/plugins/claude-ops/skills/machine-profile/SKILL.md @@ -0,0 +1,67 @@ +--- +description: "Discovers this machine's facts and identity domains, stores them as a re-runnable profile, and reports drift between the stored profile and the host now. Read-only unless the operator confirms a write. Use when: 'machine profile', 'profile this machine', 'what does this host have configured', 'has this machine changed', 'diff my machine profile', 'which identity domains exist here', 'hand my machine facts to setup'. Never installs and never reapplies a stored value on its own." +argument-hint: "[profile | diff | explain | apply --option ]" +user-invocable: true +disable-model-invocation: false +metadata: + workflow-stage: operator + summary: Discover, store and diff machine facts and per-tree identity domains. Read-only by default. + cadence: on-demand +--- + +## Purpose + +Record, once per machine, what the host has and which identity domains it holds, with the observation behind every value, so a plugin `setup` run starts from observed answers and a kept default says whether anyone looked. The profile drives setups; it never replaces their prerequisite logic. Design and rulings: `docs/specs/machine-profile-design.md`, placement in ADR 0041. + +Everything here is read-only except two steps the operator confirms in that turn: `record --confirm` (writes the profile document) and `apply --confirm` (prints what to hand to each setup; it writes nothing itself). + +## Actions + +`