diff --git a/README.md b/README.md index 368927c..c79e7ad 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,9 @@ Track work across the four RHDH Jira projects. - **[plan](./skills/rhdh-jira/references/plan.md)** — Sprint planning prep: carryover report, velocity trend, per-member capacity, ready-for-planning queue, and sprint fill suggestions with expertise matching. - **[sprint-report](./skills/rhdh-jira/references/sprint-report.md)** — Sprint review summary: committed vs completed, per-member breakdown, epic progress, demo checklist with naming conventions, and velocity trend. - **[release](./skills/rhdh-jira/references/release.md)** — Release readiness: feature matrix, Program Increment funnel, epic roll-up, cross-team dependency map, blocker bugs, release notes readiness, and risk assessment. - - **[to-feature](./skills/rhdh-jira/references/to-feature.md)** — Create a RHDHPLAN Feature from conversation context. Grills on scope, customer value, and acceptance criteria. Optionally chains into Epic decomposition. - - **[to-epic](./skills/rhdh-jira/references/to-epic.md)** — Create an RHIDP Epic. Grills on delivery scope, dependencies, and acceptance criteria. Optionally chains into Story/Task decomposition. - - **[to-issue](./skills/rhdh-jira/references/to-issue.md)** — Create a Story, Task, Bug, or Spike with automatic type inference. Grills on implementation details and story points. + - **[to-feature](./skills/rhdh-jira/references/to-feature.md)** — Create a RHDHPLAN Feature from conversation context. Grills on scope, customer value, and acceptance criteria. Optionally chains into Epic decomposition. **Requires** Matt Pocock's [`grilling`](https://github.com/mattpocock/skills) skill (see [Hard prerequisite: grilling](#hard-prerequisite-grilling)). + - **[to-epic](./skills/rhdh-jira/references/to-epic.md)** — Create an RHIDP Epic. Grills on delivery scope, dependencies, and acceptance criteria. Optionally chains into Story/Task decomposition. **Requires** [`grilling`](https://github.com/mattpocock/skills). + - **[to-issue](./skills/rhdh-jira/references/to-issue.md)** — Create a Story, Task, Bug, or Spike with automatic type inference. Grills on implementation details and story points. **Requires** [`grilling`](https://github.com/mattpocock/skills). - **[update-jira-status](./skills/rhdh-jira/references/update-jira-status.md)** — Update an issue with session progress. Detects the related issue, adds a status comment, proposes transitions, and checks upward cascade to parent Epic/Feature. ### PR Workflow @@ -143,7 +143,7 @@ Decide where a test belongs across the RHDH ecosystem — which repo, which laye ### Meta -- **[skill-maker](./skills/skill-maker/SKILL.md)** — Create new skills or consolidate existing ones following the [Agent Skills open standard](https://agentskills.io/specification). Interviews you about scope and edge cases before drafting. +- **[skill-maker](./skills/skill-maker/SKILL.md)** — Create new skills or consolidate existing ones following the [Agent Skills open standard](https://agentskills.io/specification). Interviews you about scope and edge cases before drafting. The create/interview path **requires** Matt Pocock's [`grilling`](https://github.com/mattpocock/skills) skill (see [Hard prerequisite: grilling](#hard-prerequisite-grilling)). ## Getting Started @@ -165,6 +165,22 @@ Decide where a test belongs across the RHDH ecosystem — which repo, which laye On the first run, `rhdh` auto-detects your local checkouts and creates `~/.config/rhdh-skill/config.json`. If a repo isn't found automatically, the agent will ask you for its path. +### Hard prerequisite: grilling + +Create/interview grills in **skill-maker** and **rhdh-jira** (`to-feature`, `to-epic`, `to-issue`) hard-require Matt Pocock's [`grilling`](https://github.com/mattpocock/skills/tree/main/skills/productivity/grilling) skill. Those paths run a setup check; if `grilling` is missing, the agent prompts you to confirm and installs it. + +Minimal install (what the gate installs after confirm): + +```bash +npx skills@latest add mattpocock/skills --skill grilling -g -y +``` + +**Recommended:** install the full [mattpocock/skills](https://github.com/mattpocock/skills) set — it includes other high-value engineering and productivity skills beyond `grilling`: + +```bash +npx skills@latest add mattpocock/skills --all -g +``` + ## Installation ### Global install (recommended) diff --git a/skills/rhdh-jira/SKILL.md b/skills/rhdh-jira/SKILL.md index d9091a8..b0aa004 100644 --- a/skills/rhdh-jira/SKILL.md +++ b/skills/rhdh-jira/SKILL.md @@ -1,7 +1,7 @@ --- name: rhdh-jira description: | - Interacts with RHDH Jira projects (RHIDP, RHDHPLAN, RHDHBUGS, RHDHSUPP) using acli, GraphQL, and REST API. Covers the full Jira lifecycle: create issues, assign, refine, plan sprints, report, track releases, and update status. Trigger on Jira keys (RHIDP-1234), "create a feature/epic/story/task/bug", "who should take this", "refine this", "plan the sprint", "sprint report", "release status", "update jira", or any sprint ceremony prep. + Interacts with RHDH Jira projects (RHIDP, RHDHPLAN, RHDHBUGS, RHDHSUPP) using acli, GraphQL, and REST API. Covers the full Jira lifecycle: create issues, assign, refine, plan sprints, report, track releases, and update status. Trigger on Jira keys (RHIDP-1234), "create a feature/epic/story/task/bug", "grill this", "from a support case", "customer engagement", "who should take this", "refine this", "plan the sprint", "sprint report", "release status", "update jira", or any sprint ceremony prep. compatibility: "acli (Atlassian CLI) on PATH. Python 3 for scripts. Windows, macOS, Linux." --- @@ -11,23 +11,39 @@ compatibility: "acli (Atlassian CLI) on PATH. Python 3 for scripts. Windows, mac Foundational skill for interacting with RHDH's Jira instance via the Atlassian CLI (`acli`). Covers all four active projects, issue types, workflows, custom fields, and JQL patterns. +1. **API order:** acli → GraphQL (bulk reads) → REST (writes/fallback). Prefer the lightest tool that fits. +2. **Customer identity:** Prefer support case key in summary/description; apply `RHDH-Customer` as a Jira label; put names only in restricted-visibility comments. Never put customer names in unprotected fields — see `references/fields.md`. +3. **Create paths hard-require grilling:** Before `to-feature` / `to-epic` / `to-issue`, load `references/grill.md` → Grilling prerequisite. Invoke the installed `grilling` skill once for Fill Gaps + Challenge; do not re-implement cadence here. +4. **Mutations need `--yes`; formatted descriptions need ADF.** Interactive prompts hang without `--yes`. Wiki markup in description files renders as literals — convert via `scripts/jira-wiki-to-adf.py`. +5. **"Feature Exploration" ≠ "Feature Refinement."** The meeting/process is Feature Exploration; the Jira status is Refinement. + -## Commands - -| Command | Description | Reference | -|---------|-------------|-----------| -| `assign [issue key(s) or JQL]` | Recommend and assign team members using expertise, capacity, and context proximity analysis | [references/assign.md](references/assign.md) | -| `refine [issue key(s), JQL, or 'sprint']` | Check issues against exit criteria, identify duplicates, missing fields, unaddressed comments, and readiness | [references/refine.md](references/refine.md) | -| `plan [team]` | Sprint planning prep: carryover, velocity, capacity, ready queue, sprint fill suggestions | [references/plan.md](references/plan.md) | -| `sprint-report [team]` | Sprint review summary: committed vs completed, per-member breakdown, demo checklist | [references/sprint-report.md](references/sprint-report.md) | -| `release [version]` | Release readiness: feature matrix, PI funnel, dependency map, blocker bugs, risk assessment | [references/release.md](references/release.md) | -| `to-feature [description]` | Create a RHDHPLAN Feature with grill, duplicate check, and optional Epic decomposition | [references/to-feature.md](references/to-feature.md) | -| `to-epic [description]` | Create an RHIDP Epic with grill, duplicate check, and optional Story/Task decomposition | [references/to-epic.md](references/to-epic.md) | -| `to-issue [description]` | Create a Story, Task, Bug, or Spike with automatic type inference and grill | [references/to-issue.md](references/to-issue.md) | -| `update-jira-status [key]` | Update issue with session progress, status comment, transition, and upward cascade | [references/update-jira-status.md](references/update-jira-status.md) | +## What would you like to do? + +1. **assign** — Recommend and assign team members (expertise, capacity, context proximity) +2. **refine** — Check issues against exit criteria, duplicates, missing fields, readiness +3. **plan** — Sprint planning prep: carryover, velocity, capacity, ready queue, fill suggestions +4. **sprint-report** — Sprint review summary: committed vs completed, demo checklist +5. **release** — Release readiness: feature matrix, PI funnel, blockers, risk +6. **to-feature** — Create a RHDHPLAN Feature (grill + duplicate check + optional Epic decomposition) +7. **to-epic** — Create an RHIDP Epic (grill + duplicate check + optional Story/Task decomposition) +8. **to-issue** — Create a Story, Task, Bug, or Spike (type inference + grill) +9. **update-jira-status** — Session progress comment, transition, upward cascade + +| Command | Reference | +|---------|-----------| +| `assign [issue key(s) or JQL]` | [references/assign.md](references/assign.md) | +| `refine [issue key(s), JQL, or 'sprint']` | [references/refine.md](references/refine.md) | +| `plan [team]` | [references/plan.md](references/plan.md) | +| `sprint-report [team]` | [references/sprint-report.md](references/sprint-report.md) | +| `release [version]` | [references/release.md](references/release.md) | +| `to-feature [description]` | [references/to-feature.md](references/to-feature.md) | +| `to-epic [description]` | [references/to-epic.md](references/to-epic.md) | +| `to-issue [description]` | [references/to-issue.md](references/to-issue.md) | +| `update-jira-status [key]` | [references/update-jira-status.md](references/update-jira-status.md) | Single source of truth for command descriptions: `scripts/command-metadata.json` @@ -39,9 +55,13 @@ Single source of truth for command descriptions: `scripts/command-metadata.json` ### Routing rules -1. **No argument**: Show the command menu. Ask what to do. +1. **No argument**: Show the numbered menu above. Ask what to do. 2. **First word matches a command**: Load its reference file and follow it. -3. **First word doesn't match**: General Jira invocation using the full argument as context — use the reference files table below to decide what to load. +3. **Natural-language create phrases** (any position): map to the create refs so the grilling gate loads: + - "create a feature" / "create feature" → `references/to-feature.md` + - "create an epic" / "create epic" → `references/to-epic.md` + - "create a story" / "create story" / "create a task" / "create task" / "create a bug" / "create bug" / "create a spike" / "create spike" → `references/to-issue.md` +4. **First word doesn't match**: General Jira invocation using the full argument as context — use the reference files table below to decide what to load. @@ -59,9 +79,14 @@ The script checks: 2. Jira API token auth configured (`~/.config/acli/jira_config.yaml`) 3. `.jira-token` file next to `acli` executable (for REST API fallback) 4. Smoke test against `redhat.atlassian.net` +5. Matt Pocock's `grilling` skill (`grilling/SKILL.md`) — reported in full mode; hard-gated via `--grilling-only` for create paths If `acli` is not installed, download from [Atlassian CLI](https://developer.atlassian.com/cloud/acli/) and follow the [Getting Started guide](https://developer.atlassian.com/cloud/acli/guides/how-to-get-started/) for installation and authentication setup. Use API token authentication, not OAuth — OAuth sessions expire and `acli auth status` gives false negatives with token auth (see Gotchas). +### Grilling skill gate (create/grill paths only) + +Load `references/grill.md` → Grilling prerequisite and Validate before creating. Create paths hard-require grilling; other commands do not. Full install dialogue and invoke criterion live only in `grill.md`. + ### API preference order All operations follow this priority: **acli → GraphQL → REST API**. @@ -84,11 +109,11 @@ Before attempting any REST API or GraphQL call: | Script | Purpose | |--------|---------| -| `scripts/setup.py` | Verify acli install + auth. Run with `--json` for structured output. | +| `scripts/setup.py` | Verify acli install + auth; also detects grilling skill. `--json` for structured output. `--grilling-only` for create/grill gate (exit non-zero if grilling missing). | | `scripts/parse_issues.py` | Flatten, enrich, and filter acli JSON output. Solves the core problem: `acli search --json` can't return custom fields (team, story points, sprint). Pipe search results in, get clean data out. Use `--enrich` to fetch full fields, `-f team="X"` to filter by team. | | `scripts/command-metadata.json` | Single source of truth for sub-command descriptions and argument hints. | | `scripts/validate_components.py` | Validate `references/fields.md` component catalog against live Jira projects (RHIDP + RHDHPLAN). Reports drift in both directions. Run with `--json` for structured output. | -| `scripts/jira-wiki-to-adf.py` | Convert a filled Jira wiki markup template to Atlassian Document Format JSON for use with `acli --description-file`. Handles `hN.` headings, `* ` bullets, `# ` ordered lists, `(?)` / `(/)` task items, `*bold*`, `_italic_`, `{{monospace}}`, backtick code. Usage: `python scripts/jira-wiki-to-adf.py input.txt > output.adf.json` | +| `scripts/jira-wiki-to-adf.py` | Convert a filled Jira wiki markup template to Atlassian Document Format JSON for use with `acli --description-file`. Handles `hN.` headings, `*` bullets, `#` ordered lists, `(?)` / `(/)` task items, `*bold*`, `_italic_`, `{{monospace}}`, backtick code. Usage: `python scripts/jira-wiki-to-adf.py input.txt > output.adf.json` | ## Projects @@ -120,7 +145,7 @@ Load only what the current task requires. | File | Load when... | |------|-------------| | `references/acli-commands.md` | Running an acli command you haven't used before, or hitting unexpected flag behavior. Quick reference for syntax, flag differences, and output formats. | -| `references/fields.md` | Need to know a field name, custom field ID, accepted values, or label conventions. Custom fields, labels, link types, components, priorities. | +| `references/fields.md` | Need to know a field name, custom field ID, accepted values, or label conventions. Custom fields, labels (`RHDH-Customer`), customer identity in unprotected fields, link types, components, priorities. | | `references/workflows.md` | Transitioning issues, checking exit criteria, or verifying readiness for the next status. | | `references/templates.md` | Creating new issues. Also load `references/workflows.md` for required fields at entry status. | | `references/support.md` | Handling support cases, filing bugs from customer cases, or creating feature requests from support. Full RHDHSUPP workflow, SLA, and anti-patterns. | @@ -139,7 +164,8 @@ Load only what the current task requires. | `references/to-issue.md` | Create a Story, Task, Bug, or Spike with automatic type inference and grill. | | `references/update-jira-status.md` | Update a Jira issue with session progress, status comment, transitions, and upward cascade to parent Epic/Feature. | | `references/duplicates.md` | Duplicate detection for pre-creation checks and refinement audits. Shared across creation commands and refine. | -| `references/grill.md` | Shared challenging behavior for issue creation grills: sizing, completeness, scope, risks, cross-referencing. | +| `references/grill.md` | Shared create/grill behavior: grilling prereq (SSOT), one-shot `grilling` invoke for Fill Gaps + Challenge, domain challenges, customer/label pre-create checks. | +| `references/work-breakdown.md` | Decomposing Feature→Epics or Epic→Stories/Tasks — synthesize-then-gap-fill, tracer bullets, blocking edges, quiz before create. | | `references/sizing.md` | T-shirt sizing guide for Features/Epics and Fibonacci story points for Stories/Tasks. Used during grills and refinement. | @@ -171,6 +197,7 @@ Load only what the current task requires. | Error | Action | |-------|--------| | `acli` not on PATH | Run `scripts/setup.py`. Install from Atlassian if missing. See [Getting Started](https://developer.atlassian.com/cloud/acli/guides/how-to-get-started/). | +| grilling skill missing on create/grill | Follow `references/grill.md` → Grilling prerequisite (`setup.py --grilling-only`, confirm, install, re-check). | | "unauthorized" from `auth status` | Ignore. Check `jira_config.yaml` exists. Run smoke test. | | "required flag(s) not set" | Command syntax wrong. Run `acli jira --help`. | | "field X is not allowed" | Use `--json` instead of `--fields` for that field. | @@ -187,7 +214,7 @@ These apply across all sub-commands: - **Release Pending counts as completed.** Release Pending items remain in the sprint and count toward velocity and capacity. They represent done work awaiting release. - **Confirmation flow.** Sub-commands that modify Jira issues use a standard prompt: `"Apply changes? [y/N/edit]"` — **y** applies all, **N** cancels, **edit** steps through each change individually. - **Closure requires rationale.** When closing or descoping issues, always add a comment documenting the reason and set the resolution field (`Won't Do`, `Duplicate`, `Done`). Preserves the decision trail. -- **Comments over description bloat.** Issue descriptions use the structured template sections. Decision trail, elaboration, abandoned approaches, and customer context go in comments. Creation commands proactively suggest comments for context that emerged during the grill. +- **Comments over description bloat.** Issue descriptions use the structured template sections. Decision trail, elaboration, and abandoned approaches go in comments. Prefer support key + use case in the description; put customer-identifying detail only in restricted-visibility comments. Creation commands proactively suggest comments for context that emerged during the grill. ## Common Workflows @@ -259,13 +286,9 @@ These apply across all sub-commands: ### Creating Features, Epics, and Issues -1. Load the appropriate creation reference (`to-feature.md`, `to-epic.md`, or `to-issue.md`) -2. Load `references/grill.md` for challenging behavior -3. Load the template + example pair from `assets/templates/` and `assets/examples/` -4. Grill the user on scope, AC, sizing (reference `references/sizing.md`) -5. Run duplicate check per `references/duplicates.md` -6. Create the issue, suggest comments for decision trail -7. Offer chained decomposition (Feature → Epics → Stories/Tasks) +1. Load the appropriate creation reference (`to-feature.md`, `to-epic.md`, or `to-issue.md`) — NL phrases like "create a feature" route here too +2. Follow that ref: grilling prereq from `grill.md`, load sizing/fields, invoke `grilling` once for Fill Gaps + Challenge, validate, duplicate-check, create +3. Offer chained decomposition (Feature → Epics → Stories/Tasks) using `references/work-breakdown.md` (tracer bullets + blocking edges; quiz before create) ### Updating Jira from a session diff --git a/skills/rhdh-jira/assets/examples/feature-example.txt b/skills/rhdh-jira/assets/examples/feature-example.txt index aa249e5..666fc5c 100644 --- a/skills/rhdh-jira/assets/examples/feature-example.txt +++ b/skills/rhdh-jira/assets/examples/feature-example.txt @@ -23,7 +23,7 @@ h3. *Out of Scope (Optional)* h3. *Customer Considerations (Optional)* -Large enterprise customers (500+ developers) have expressed this as a top-3 need. Current workaround is running separate RHDH instances per catalog source, which increases operational overhead and fragments the developer experience. +Raised via CASE-12345 — platform-engineer persona managing 500+ developers across multiple SCM backends. Top-3 need: unify catalog sources in one RHDH instance. Current workaround is separate RHDH instances per catalog source (operational overhead + fragmented search). Apply label: RHDH-Customer. h3. *Documentation Considerations* diff --git a/skills/rhdh-jira/assets/templates/feature.txt b/skills/rhdh-jira/assets/templates/feature.txt index 4cc08b9..7ec3f17 100644 --- a/skills/rhdh-jira/assets/templates/feature.txt +++ b/skills/rhdh-jira/assets/templates/feature.txt @@ -24,7 +24,7 @@ High-level list of items that are out of scope. h3. *Customer Considerations (Optional)* -Provide any additional customer-specific considerations that must be made when designing and delivering the Feature. Initial completion during Refinement status. +Provide non-identifying customer considerations for designing and delivering the Feature (support-ticket keys, personas, use cases). Do not put customer names in this unprotected field — use the RHDH-Customer label and restricted-visibility comments for identity. Initial completion during Refinement status. diff --git a/skills/rhdh-jira/references/acli-commands.md b/skills/rhdh-jira/references/acli-commands.md index 63caa36..35cceb7 100644 --- a/skills/rhdh-jira/references/acli-commands.md +++ b/skills/rhdh-jira/references/acli-commands.md @@ -59,7 +59,7 @@ acli jira workitem view RHIDP-123 --web acli jira workitem create --project RHIDP --type Story --summary "Implement auth plugin" --description "As a user..." --assignee "@me" # With labels -acli jira workitem create --project RHDHBUGS --type Bug --summary "Login fails" --label "rhdh-customer,ci-fail" +acli jira workitem create --project RHDHBUGS --type Bug --summary "Login fails" --label "RHDH-Customer,ci-fail" # With parent (sub-task or child of epic) acli jira workitem create --project RHIDP --type Task --summary "Write tests" --parent RHIDP-12968 diff --git a/skills/rhdh-jira/references/feature-exploration.md b/skills/rhdh-jira/references/feature-exploration.md index 83a13bb..dd44297 100644 --- a/skills/rhdh-jira/references/feature-exploration.md +++ b/skills/rhdh-jira/references/feature-exploration.md @@ -59,6 +59,7 @@ Components must be accurate — they affect Feature Freeze and Code Freeze queri - `rhdh-testday` — if this feature should be tested as part of release test day - `rhdh-X.Y-candidate` — candidate for a specific release (e.g., `rhdh-2.1-candidate`) - `stretch` — stretch goal for the release (may be descoped) +- `RHDH-Customer` — if the feature originated from a support case or customer engagement (single label; never also `rhdh-customer`). Prefer support key in summary/description; apply this as a Jira label; identity only in restricted comments — see `references/fields.md`. ### 7. Create Epics for Each Scrum Team diff --git a/skills/rhdh-jira/references/fields.md b/skills/rhdh-jira/references/fields.md index 0b9035f..a119dbf 100644 --- a/skills/rhdh-jira/references/fields.md +++ b/skills/rhdh-jira/references/fields.md @@ -46,7 +46,7 @@ cf[10785] is EMPTY ## Labels -All lowercase, hyphen-separated. Labels are global to the Jira instance. +Most labels are lowercase and hyphen-separated. Labels are global to the Jira instance. **Exception:** prefer the capitalization `RHDH-Customer` when applying that label (see below). | Label | Usage | |-------|-------| @@ -60,11 +60,25 @@ All lowercase, hyphen-separated. Labels are global to the Jira instance. | `ci-fail` | Identifies CI failures | | `must-have` | Documentation team — must-have for release doc plan | | `nice-to-have` | Documentation team — nice-to-have for release doc plan | -| `rhdh-customer` | Issues from customer interactions (support cases, engagements) | +| `RHDH-Customer` | Issues from customer interactions (support cases, engagements). **Preferred capitalization.** Apply this label alone — never also apply `rhdh-customer`. Jira label search is case-insensitive, so both spellings collide in search. | | `ga-support` | Target support level: GA (generally available) | | `tp-support` | Target support level: Tech Preview | | `dp-support` | Target support level: Developer Preview | +### Customer identity in unprotected fields (authoritative) + +Do not put customer names or other customer-identifying detail in unprotected fields (summary, description, and other public/default-visibility fields). + +**Preferred pattern:** + +1. Reference the support ticket / case key (or similar non-identifying handle) in summary/description when needed. +2. Apply a single `RHDH-Customer` label for customer-origin work. +3. Put customer-identifying detail only in comments with appropriate restricted visibility (e.g. RH employee-only) when the project supports security levels — or keep identity out of Jira fields entirely and rely on the support-system link. + +**Label rule:** Prefer one `RHDH-Customer` label. Never apply both `RHDH-Customer` and `rhdh-customer`. + +Enforce these checks on every create/grill path before create (`to-feature`, `to-epic`, `to-issue`, and shared `references/grill.md`). See also `references/support.md` for RHDHSUPP ↔ RHDHBUGS project boundaries. + ## Link Types Match by **name** in `issuelinks`, not by ID. diff --git a/skills/rhdh-jira/references/grill.md b/skills/rhdh-jira/references/grill.md index ffb6db1..d558370 100644 --- a/skills/rhdh-jira/references/grill.md +++ b/skills/rhdh-jira/references/grill.md @@ -4,9 +4,26 @@ Shared challenging behavior for issue creation workflows. Each caller defines it Load this alongside the command's type-specific questions. Apply every applicable behavior during the grill — don't skip challenges to be polite. +Create commands load `references/sizing.md` and `references/fields.md` before the grill. Do not load those files from here. + ## Cadence -Ask one question at a time. Wait for the answer before asking the next. Adapt follow-ups based on what you learn. If the conversation already established context (e.g., chained from a parent issue), don't re-ask — carry it forward. +**Invoke the installed `grilling` skill once covering Fill Gaps + Challenge** (read its SKILL.md and follow it; `/grilling` if host supports slash-commands). Do not re-implement cadence in this skill. + +**Grill complete when:** every applicable Challenge Behavior from the matrix below has been applied (or explicitly skipped with a reason), inferred fields are confirmed, and Validate before creating passes. + +Domain-specific challenges below stay in this skill. If the conversation already established context (e.g., chained from a parent issue), don't re-ask — carry it forward. + +### Grilling prerequisite + +Before any create/grill path (`to-feature`, `to-epic`, `to-issue`): + +1. Run `python scripts/setup.py --grilling-only --json` and check `grilling_found`. +2. If missing: hard-stop. State that Matt Pocock's `grilling` skill is required. Recommend the full pack (`npx skills@latest add mattpocock/skills --all -g`). Ask for confirmation, then install the minimal command from the setup output (`minimal_install`). Re-run the check. Continue only when `grilling_found` is true. +3. The setup script detects only — it does not install. Confirm + install are owned by this skill. +4. Use `--grilling-only` so acli/auth failures do not hide the grilling-specific message. + +Do **not** gate refine/assign/plan/sprint-report/release/update-jira-status on grilling. ## Field Inference @@ -21,7 +38,7 @@ After the grill questions are complete, present all inferred fields at once: > - **Size**: M (3) — cross-team coordination + 4 AC items suggests ~3 sprints > - **Component**: Plugins — primary area of change > - **Assignee**: Allison Hill — top expertise in plugins per assign analysis -> - **Labels**: `rhdh-2.1-candidate`, `demo` — customer-facing feature targeting 2.1 +> - **Labels**: `rhdh-2.1-candidate`, `demo`, `RHDH-Customer` — customer-origin feature (CASE-12345) targeting 2.1 > > "Adjust any of these? [y to confirm / list changes]" @@ -31,10 +48,10 @@ After the grill questions are complete, present all inferred fields at once: |-------|------------| | **Priority** | Severity of the problem, customer impact, blocker language, urgency words. Default to Major unless clear signals suggest otherwise. | | **Team** | Components mentioned, domain area, who the user is, parent issue's team, which team owns the affected code. | -| **Size** | AC count, dependency count, complexity signals from the grill ("need to investigate", "multiple PRs", "cross-team"). Cross-reference against `references/sizing.md`. | -| **Component** | Technical domain discussed (RBAC, plugins, catalog, helm, operator, CI/CD, docs). Match against known components in `references/fields.md`. Also check codebase context — if the user has been editing files during the session, infer from file paths (see below). | +| **Size** | AC count, dependency count, complexity signals from the grill ("need to investigate", "multiple PRs", "cross-team"). Use the sizing guide already loaded by the create command. | +| **Component** | Technical domain discussed (RBAC, plugins, catalog, helm, operator, CI/CD, docs). Match against known components (catalog already loaded via create command). Also check codebase context — if the user has been editing files during the session, infer from file paths (see below). | | **Assignee** | If the user is describing their own work, suggest them. Otherwise, run a lightweight expertise match from the conversation context (component + domain keywords against team roster). For deep analysis, suggest running `assign`. | -| **Labels** | Customer-facing → `demo`. Release target mentioned → `rhdh-X.Y-candidate`. Stretch goal language → `stretch`. Support origin → `rhdh-customer`. | +| **Labels** | Customer-facing → `demo`. Release target mentioned → `rhdh-X.Y-candidate`. Stretch goal language → `stretch`. Support/customer origin → single `RHDH-Customer` (never also apply `rhdh-customer`). | ### Codebase-aware component inference @@ -77,7 +94,7 @@ After the user proposes a size (T-shirt or story points): - Count the acceptance criteria items. If the AC count seems high for the proposed size, push back: "You have {N} acceptance criteria items — is {size} realistic?" - Check for cross-team dependencies. Dependencies add coordination overhead that inflates effort. - Check for unknowns. If the user said "we need to investigate" or "not sure about," that's a spike signal — suggest time-boxing or splitting the unknown into a separate spike. -- Cross-reference against the sizing guide. Load `references/sizing.md` for T-shirt size definitions (Features/Epics) and Fibonacci story point scale (Stories/Tasks). +- Cross-reference against the sizing guide already loaded by the create command (T-shirt for Features/Epics; Fibonacci for Stories/Tasks). ### Challenge completeness @@ -160,12 +177,18 @@ Keep this lightweight. One search during the grill is enough — don't run a sea ### Validate before creating -Before proceeding to creation, verify the issue would pass the entry-status exit criteria from `references/workflows.md`: +Before proceeding to creation, verify the issue would pass New-status entry criteria: - Are all required fields for New status determined? (Assignee, Priority, Team, Component — varies by type) - Is the description substantive enough? A one-sentence description on a Feature is a red flag. - Is the summary clear and specific? Summaries like "Update plugins" or "Fix bug" are too vague. +Also enforce customer identity and label rules (create commands load `fields.md` for full detail): + +- **Preferred pattern:** Put support-ticket / case keys (and persona/use-case language) in summary/description when needed; apply a single `RHDH-Customer` Jira label for customer-origin work; put customer-identifying detail only in restricted-visibility comments when the project supports it. +- **Guardrail:** Never put customer names or other identifying detail in unprotected fields (summary, description, public fields). +- **Labels:** Apply exactly one `RHDH-Customer` — never both `RHDH-Customer` and `rhdh-customer` (Jira label search is case-insensitive). + If validation fails, ask the user to fill the gap rather than creating a half-baked issue. ## Applicability by Issue Type @@ -201,6 +224,6 @@ After the issue is created, proactively suggest comments for context that emerge - **Decision trail**: "We discussed [alternative] but chose [approach] because [reason]." - **Elaboration**: "Additional context about [topic] that supports the decision." - **Abandoned paths**: "Initially considered [approach], abandoned because [reason]." -- **Customer context**: "This was raised by [customer type/use case] — relevant for prioritization." +- **Customer context**: Prefer support key + use case ("Raised via CASE-123 — SSO timeout during session refresh"). Put customer-identifying detail only in a restricted-visibility comment when needed; never paste customer names into unprotected fields. Present each suggestion with a recommended comment text. The user approves, edits, or skips each one. diff --git a/skills/rhdh-jira/references/plan.md b/skills/rhdh-jira/references/plan.md index 0905613..a92e995 100644 --- a/skills/rhdh-jira/references/plan.md +++ b/skills/rhdh-jira/references/plan.md @@ -6,6 +6,8 @@ Uses GraphQL for bulk reads (skip acli). Writes follow the API preference order Authentication setup: see `references/auth.md`. All examples below assume `AUTH`, `CLOUD_ID`, and `GRAPHQL_URL` are set per that file. +**Intentional load:** Steps 4 and 7 reuse roster/capacity/expertise from `references/assign.md` Layers 1–3. Load those sections of `assign.md` only when needed — not a further hop into other refs. + ## Input The caller provides: @@ -107,10 +109,10 @@ For each ready-for-planning issue, score against each team member using the same ### Step 8 — Critical Customer Bugs -Separately surface any critical/blocker bugs with `rhdh-customer` label: +Separately surface any critical/blocker bugs with the `RHDH-Customer` label (Jira label search is case-insensitive): ```bash -jql: "project in (RHIDP, RHDHBUGS) AND priority in (Blocker, Critical) AND labels = rhdh-customer AND \"Team[Team]\" = TEAM_ID AND status != Closed" +jql: "project in (RHIDP, RHDHBUGS) AND priority in (Blocker, Critical) AND labels = \"RHDH-Customer\" AND \"Team[Team]\" = TEAM_ID AND status != Closed" ``` Note: "Critical customer bugs are exempt from capacity constraints — work immediately regardless of sprint load." diff --git a/skills/rhdh-jira/references/support.md b/skills/rhdh-jira/references/support.md index 5239376..1e5fda6 100644 --- a/skills/rhdh-jira/references/support.md +++ b/skills/rhdh-jira/references/support.md @@ -5,7 +5,7 @@ How support cases flow between RHDHSUPP, RHDHBUGS, and RHDHPLAN. ## Key Concepts - **RHDHSUPP** — Internal project for engineering-support conversations. Not public. -- **RHDHBUGS** — Public project for product defects. **Never include customer information.** +- **RHDHBUGS** — Public project for product defects. Prefer support case keys in summary/description; apply `RHDH-Customer` as a Jira label; no customer names in unprotected fields — see `references/fields.md`. - **RHDHPLAN** — Public project for feature requests. - The engineering support liaison owns the relationship with the support team. Route questions about the support process to them. @@ -65,7 +65,7 @@ When a product defect is identified: 1. Create `Bug` in **RHDHBUGS** with: - Priority, Component (use `Documentation` for doc defects) - Bug template filled out (reproduction steps, expected behavior) - - **No customer information** — RHDHBUGS is a public project + - Prefer support case key in summary/description; apply `RHDH-Customer` as a Jira label; no customer names in unprotected fields (see `references/fields.md`) - Link to Customer Case via SFDC Cases Links 2. Comment on the RHDHSUPP issue with the RHDHBUGS link — this tells the customer when the fix is expected @@ -78,7 +78,7 @@ python scripts/jira-wiki-to-adf.py bug_description.txt "$BUG_ADF" acli jira workitem create --project RHDHBUGS --type Bug \ --summary "Login fails when SSO token expires during session" \ --description-file "$BUG_ADF" \ - --label "rhdh-customer" \ + --label "RHDH-Customer" \ --assignee "@me" # Link it to the support issue @@ -184,4 +184,4 @@ These are internal documents. Do not embed their URLs in agent output or share e | RHDHBUGS | Product defects — bugs and doc defects | Yes | | RHDHPLAN | Feature requests from customers | Yes | -**Security rule:** Never copy customer-identifying information from RHDHSUPP into RHDHBUGS or RHDHPLAN. Those projects are public. +**Security rule:** Prefer support-ticket keys + a single `RHDH-Customer` label in RHDHBUGS/RHDHPLAN; put customer-identifying detail only in restricted-visibility comments when needed. Never copy customer names into unprotected fields on those public projects. See `references/fields.md` (authoritative). diff --git a/skills/rhdh-jira/references/templates.md b/skills/rhdh-jira/references/templates.md index 6bd8135..9b388e2 100644 --- a/skills/rhdh-jira/references/templates.md +++ b/skills/rhdh-jira/references/templates.md @@ -52,6 +52,7 @@ Load `references/workflows.md` for full exit criteria per status. Key fields at ## Notes - **Feature Request** and **Outcome** templates exist in RHDHPLAN but are not used by the creation sub-commands. See `references/support.md` for Feature Request creation from support cases. -- **Bugs go to RHDHBUGS**, not RHIDP. Do not include customer information in RHDHBUGS — it's a public project. +- **Bugs go to RHDHBUGS**, not RHIDP. Prefer support case keys in summary/description; apply `RHDH-Customer` as a Jira label; no customer names in unprotected fields — see `references/fields.md`. RHDHBUGS is public. +- **Field requirements at creation:** Intentional pointer to `references/workflows.md` for full exit criteria (loaded when needed; not a transitive hop from this file alone). - **Spikes** use the Task template with a `SPIKE:` prefix in the summary and a time-boxed story point estimate. - **Sub-tasks** are created as children of an existing issue, not standalone. Use `acli jira workitem create --parent KEY` for sub-tasks. diff --git a/skills/rhdh-jira/references/to-epic.md b/skills/rhdh-jira/references/to-epic.md index fcdae16..b7e708c 100644 --- a/skills/rhdh-jira/references/to-epic.md +++ b/skills/rhdh-jira/references/to-epic.md @@ -4,6 +4,10 @@ Create an RHIDP Epic from conversation context. Grills the user on delivery scop ## Workflow +### Step 0 — Grilling prerequisite + +Load `references/grill.md` → Grilling prerequisite and Validate before creating. Hard-require grilling before create. Also load `references/sizing.md` and `references/fields.md` before the grill. + ### Step 1 — Determine Context Two entry modes: @@ -33,15 +37,19 @@ Skip this step for standalone Epics (no parent Feature). Load `assets/templates/epic.txt` for structure and `assets/examples/epic-example.txt` for tone calibration. -Synthesize: Draft as many template sections as possible from the conversation (and parent Feature if chained): +Synthesize per `references/work-breakdown.md`: draft from conversation (and parent Feature if chained); do not re-ask settled Feature-level topics: - EPIC Goal, Background/Feature Origin, Why important, User Scenarios, Dependencies, AC -If chained from a Feature, pre-fill: Goal (scoped to this team's delivery), Background (link to parent Feature), Dependencies (other Epics in the Feature). +If chained from a Feature, pre-fill: Goal (scoped to this team's delivery), Background (link to parent Feature), Dependencies / **blocking edges** (other Epics in the Feature). + +When drafting customer-origin context, one-line check against `references/fields.md`: support case key / persona / use case — no customer names. Present the draft: "Here's what I have for this Epic. Review and tell me what's missing." -### Step 3 — Fill Gaps +### Step 3 — Fill Gaps + Challenge + +Invoke the installed `grilling` skill once covering Fill Gaps + Challenge (read its SKILL.md and follow it; `/grilling` if host supports slash-commands). Do not re-implement cadence in this skill. Apply domain challenges from `references/grill.md`. For unfilled sections, ask targeted questions. Adapt based on entry mode: @@ -54,7 +62,7 @@ For unfilled sections, ask targeted questions. Adapt based on entry mode: **Standalone (full):** 1. **EPIC Goal** — what are we trying to solve? -2. **Background/Feature Origin** — where did this come from? +2. **Background/Feature Origin** — where did this come from? (support case key / persona / use case — no customer names; see `references/fields.md`) 3. **Why is this important?** 4. **User Scenarios** — who benefits and how? 5. **Dependencies** — internal and external @@ -62,11 +70,7 @@ For unfilled sections, ask targeted questions. Adapt based on entry mode: Skip questions the draft already answered. -### Step 4 — Challenge - -Follow the challenging behavior in `references/grill.md`. - -### Step 5 — Infer Fields +### Step 4 — Infer Fields Infer all Jira fields per `references/grill.md` Field Inference. If chained, inherit Priority and Team from parent Feature. Key fields: Team, Priority, Size (T-shirt), Component, Assignee (Epic Owner). @@ -74,12 +78,15 @@ Infer all Jira fields per `references/grill.md` Field Inference. If chained, inh **Dependencies:** Link or note key dependencies on other issues, teams, or upstream work. -### Step 6 — Review +**Customer identity + labels:** Prefer support key in summary/description; apply `RHDH-Customer` as a Jira label for customer-origin work; put customer-identifying detail only in restricted-visibility comments. Never also apply `rhdh-customer`. See `references/fields.md`. -Render the filled template and inferred fields as a temporary markdown file for user review: +### Step 5 — Review + +Render the filled template and inferred fields as a temporary markdown file for user review. Use a portable temp path (`$TMPDIR` / `%TEMP%` / Python `tempfile`): ```bash -cat > /tmp/epic-review.md << 'EOF' +REVIEW=$(mktemp "${TMPDIR:-/tmp}/epic-review.XXXXXX.md") # Windows: %TEMP%\epic-review.md or tempfile +cat > "$REVIEW" << 'EOF' ## Epic: {summary} ### Description @@ -96,11 +103,13 @@ EOF Present to the user: "Review the Epic before creating. [approve / edit / cancel]" -### Step 7 — Duplicate Check +### Step 6 — Duplicate Check Run the pre-creation check from `references/duplicates.md`. Search RHIDP Epics (`issuetype = Epic`). -### Step 8 — Create Epic +### Step 7 — Create Epic + +Before create: re-check customer identity + label rules per `references/grill.md` → Validate before creating. Fill the template. Then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`: @@ -135,36 +144,37 @@ curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \ Set Team via REST — follow API preference order in SKILL.md. -### Step 9 — Comments +### Step 8 — Comments Follow the comment suggestion behavior from `references/grill.md` — proactively suggest decision trail, elaboration, and abandoned paths as comments. Add via `acli jira workitem comment --key RHIDP-XXX --comment "text" --yes`. -### Step 10 — Chain Decomposition +### Step 9 — Chain Decomposition After the Epic is created: > "Break this Epic into Stories/Tasks? [y/N]" -If yes: +If yes, load `references/work-breakdown.md` and: -1. Discuss the breakdown: what are the deliverable slices? -2. For each slice, invoke the `to-issue` workflow with context carried down: - - The Epic's goal, AC, and dependencies are established - - The issue grill narrows to: implementation specifics, story points, approach -3. Each Story/Task is automatically linked to the parent Epic via `parent` field -4. Type inference runs per slice (Story if user-facing, Task if internal) +1. Draft **tracer bullet** slices (vertical, demoable/verifiable) — not horizontal backend/frontend/docs splits for the same behaviour. Prefer a prefactor/spike first when unknowns block slicing. +2. Present a numbered batch with **Blocked by** per slice. Quiz granularity and edges before creating any issue. +3. For each approved slice, invoke the `to-issue` workflow with context carried down: + - Epic goal, AC, and dependencies are established + - Issue grill narrows to: implementation specifics, story points, approach +4. Link each Story/Task to the parent Epic via `parent`. Type inference per slice (Story if user-facing, Task if internal). +5. Create in dependency order when practical (blockers first); set `Blocks` / Dependency text when edges are real. #### Batch Review (Feature → Epics) -When decomposing a Feature into multiple Epics (chained creation), run a batch review before finalizing any of them: +When decomposing a Feature into multiple Epics (chained creation), run a batch review before finalizing any of them. Apply `references/work-breakdown.md` (blocking edges + quiz before create). RHDH still creates Epics **per team** — tracer-bullet slicing is stricter for Epic → Stories. -1. **Propose all Epics first**: Collect the full set of proposed Epics as a summary table before creating any: +1. **Propose all Epics first**: Collect the full set as a summary table before creating any: - | # | Epic Summary | Size | Key Dependencies | Overlaps with | - |---|-------------|------|------------------|---------------| - | 1 | Entity-Provider SDK | M | upstream catalog API | — | + | # | Epic Summary | Size | Blocked by | Overlaps with | + |---|-------------|------|------------|---------------| + | 1 | Entity-Provider SDK | M | None | — | | 2 | OCI Skill Registry | S | #1 (SDK) | — | | 3 | Annotation Scheme | XS | #1 (SDK) | #1 (same package) | @@ -174,7 +184,7 @@ When decomposing a Feature into multiple Epics (chained creation), run a batch r 4. **Consolidation check**: If multiple XS/S Epics target the same technical domain, suggest merging: "Epics #1 and #3 both target the SDK package — could #3 be ACs on #1?" -5. **User decides**: Allow the user to merge, drop, or proceed before creation begins. Only create Epics after the batch is approved. +5. **User decides**: Merge, drop, or proceed before creation begins. Only create Epics after the batch is approved. ## Error Handling @@ -190,4 +200,4 @@ When decomposing a Feature into multiple Epics (chained creation), run a batch r 1. **Epic Owner responsibility.** The assignee is the Epic Owner — single point of contact for delivery, works with the Feature Owner to align execution. The Epic Owner is responsible for sizing the Epic. 2. **Component is required at New status.** Don't skip this during the grill. Validate against `references/fields.md` → Component Validation. 3. **Multi-team Features create multiple Epics.** When chained from a Feature, each team gets its own Epic. The Feature Owner coordinates across them. -4. **Size via sizing guide.** Use T-shirt sizing per `references/sizing.md`. If the parent Feature has multiple L or XL Epics, flag for the Feature Owner — the Feature scope may need reassessment. +4. **Size via sizing guide.** Use T-shirt sizing per `references/sizing.md` (loaded in Step 0). If the parent Feature has multiple L or XL Epics, flag for the Feature Owner — the Feature scope may need reassessment. diff --git a/skills/rhdh-jira/references/to-feature.md b/skills/rhdh-jira/references/to-feature.md index e828144..7f695a5 100644 --- a/skills/rhdh-jira/references/to-feature.md +++ b/skills/rhdh-jira/references/to-feature.md @@ -4,35 +4,41 @@ Create a RHDHPLAN Feature from conversation context. Grills the user on scope, c ## Workflow +### Step 0 — Grilling prerequisite + +Load `references/grill.md` → Grilling prerequisite and Validate before creating. Hard-require grilling before create. Also load `references/sizing.md` and `references/fields.md` before the grill. + ### Step 1 — Draft from Context -Load `assets/templates/feature.txt` for structure and `assets/examples/feature-example.txt` for tone calibration. +Load `assets/templates/feature.txt` for structure and `assets/examples/feature-example.txt` for tone calibration. Apply **synthesize, then grill gaps** from `references/work-breakdown.md`: fill from conversation first; do not re-ask settled topics. -Before asking questions, review what the conversation already established. Draft as many template sections as possible from existing context: +Draft as many template sections as possible from existing context: - Feature Overview, Goals, AC, Out of Scope, Customer Considerations, Documentation, Upstream engagement +Fold settled **implementation / testing decisions** from the chat into AC or Out of Scope (or note them for a comment after create) so they are not lost. Keep the RHDH Feature template — do not switch to a generic PRD. + +When drafting **Customer Considerations**, one-line check against `references/fields.md`: use support case key / persona / use case only — no customer names. + Present the draft: "Based on our conversation, here's what I have so far. Review and tell me what's missing or wrong." -### Step 2 — Fill Gaps +### Step 2 — Fill Gaps + Challenge + +Invoke the installed `grilling` skill once covering Fill Gaps + Challenge (read its SKILL.md and follow it; `/grilling` if host supports slash-commands). Do not re-implement cadence in this skill. Apply domain challenges from `references/grill.md` on the completed draft. -For any template sections the agent couldn't fill from context, ask targeted questions (one at a time): +For any template sections the agent couldn't fill from context, ask targeted questions: 1. **Feature Overview** — what is this? Elevator pitch. 2. **Goals** — what does the user get? Which persona benefits? 3. **Requirements / Acceptance Criteria** — what must be true for this to be complete? Include non-functional requirements. 4. **Out of Scope** — what is explicitly NOT included? -5. **Customer Considerations** — any customer-specific context? +5. **Customer Considerations** — support case key / persona / use case — no customer names; see `references/fields.md` 6. **Documentation Considerations** — what docs need creating/updating? 7. **Upstream engagement** — does this need Backstage community alignment? Skip questions the draft already answered well. -### Step 3 — Challenge - -Follow the challenging behavior in `references/grill.md` on the completed draft. - -### Step 4 — Infer Fields +### Step 3 — Infer Fields Infer all Jira fields from the conversation per the Field Inference section in `references/grill.md`. Present recommendations for confirmation. @@ -48,18 +54,21 @@ Key fields for Features: Priority, Team, Size (T-shirt), Assignee (Feature Owner | `rhdh-testday` | Should this feature be tested during release test day? | | `rhdh-X.Y-candidate` | Which release does this target? | | `stretch` | Is this a stretch goal? | +| `RHDH-Customer` | Did this originate from a support case or customer engagement? If yes, apply a single `RHDH-Customer` label (never also `rhdh-customer`). | + +**Customer identity (before create):** Prefer support key in summary/description; apply `RHDH-Customer` as a Jira label; put customer-identifying detail only in restricted-visibility comments. See `references/fields.md`. **Documentation:** If the feature involves documentation, set the `Documentation` component. After creation, prompt: "Create a Doc EPIC from this Feature? (Feature → More → Create Doc EPIC from RHDHPlan)" -**Cross-team dependencies:** Ask if other scrum teams are affected. If yes, note them — they become Epics in Step 9. +**Cross-team dependencies:** Ask if other scrum teams are affected. If yes, note them — they become Epics in Step 8. -### Step 5 — Review +### Step 4 — Review -Render the filled template and inferred fields as a temporary markdown file for user review: +Render the filled template and inferred fields as a temporary markdown file for user review. Use a portable temp path (`$TMPDIR` / `%TEMP%` / Python `tempfile`): ```bash -# Save to temp file -cat > /tmp/feature-review.md << 'EOF' +REVIEW=$(mktemp "${TMPDIR:-/tmp}/feature-review.XXXXXX.md") # Windows: %TEMP%\feature-review.md or tempfile +cat > "$REVIEW" << 'EOF' ## Feature: {summary} ### Description @@ -80,7 +89,7 @@ Present to the user: "Review the Feature before creating. Edit the file or tell - **edit** — user modifies the file or provides changes verbally, agent updates - **cancel** — abort creation -### Step 6 — Duplicate Check and Feature Request Link +### Step 5 — Duplicate Check and Feature Request Link Before creating, run the pre-creation check from `references/duplicates.md` using the proposed summary. Search RHDHPLAN Features specifically (`issuetype = Feature`). @@ -94,7 +103,9 @@ If a matching Feature Request is found: "Found accepted Feature Request {KEY}: { If a likely duplicate Feature is found, present it and ask: "This may already exist as {KEY}: {summary}. Use the existing issue instead?" -### Step 7 — Create Feature +### Step 6 — Create Feature + +Before create: re-check customer identity + label rules per `references/grill.md` → Validate before creating. Strip customer names from summary/description if present; ensure at most one `RHDH-Customer` label. Fill the template with grill results. Save to a temp file. Then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`: @@ -128,7 +139,7 @@ curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \ Set Team via REST — follow API preference order in SKILL.md. -### Step 8 — Comments +### Step 7 — Comments Follow the comment suggestion behavior from `references/grill.md` — proactively suggest decision trail, elaboration, and abandoned paths as comments. @@ -138,19 +149,21 @@ Add each approved comment via: acli jira workitem comment --key RHDHPLAN-XXX --comment "comment text" --yes ``` -### Step 9 — Chain Decomposition +### Step 8 — Chain Decomposition After the Feature is created: > "Break this Feature into Epics? The RHDH process typically creates Epics per team (Eng, QE, Doc). [y/N]" -If yes: +If yes, load `references/work-breakdown.md` and: 1. Ask: "Which teams are involved?" Default suggestion: Eng + Doc (QE is often covered within the Eng epic). -2. For each team, invoke the `to-epic` workflow with context carried down from this Feature: - - The Feature's scope, AC, and customer considerations are established — don't re-grill on these - - The Epic grill narrows to: delivery scope for *this team*, dependencies, team-specific AC -3. Each Epic is automatically linked to the parent Feature via `customfield_10018` (cross-project parent link — see Gotcha #16 and to-epic.md Step 8) +2. Propose the Epic batch **before creating any** (see `to-epic.md` Batch Review). For each Epic, state **blocking edges** (which other Epics must land first) and a team-scoped outcome — not a horizontal tech layer. +3. Quiz granularity / blockers / merge-split per `work-breakdown.md` → Quiz before create. Only then create. +4. For each approved Epic, invoke the `to-epic` workflow with context carried down: + - Feature scope, AC, and customer considerations are established — don't re-grill on these + - Epic grill narrows to: delivery scope for *this team*, dependencies, team-specific AC +5. Each Epic is linked to the parent Feature via `customfield_10018` (cross-project parent link — see Gotcha #16 and to-epic.md Step 7) ## Error Handling @@ -165,6 +178,6 @@ If yes: 1. **Feature Owner responsibility.** Creating a Feature implies ownership. Ensure the assignee understands the Feature Owner responsibilities (single point of contact, coordinates cross-team dependencies, ensures sizing and labels). 2. **Candidate label convention.** The label format is `rhdh-X.Y-candidate` (e.g., `rhdh-2.1-candidate`). Ask which release this targets during the grill. **Do not remove candidate labels without PM approval.** -3. **Description stays structured.** Only template sections go in the description. Decision trail, elaboration, and abandoned approaches go in comments. +3. **Description stays structured.** Only template sections go in the description. Decision trail, elaboration, abandoned approaches, and customer-identifying detail go in comments (restricted visibility when needed). Prefer support key in summary/description; apply `RHDH-Customer` as a Jira label — see `references/fields.md`. 4. **Rescoping.** If the feature is too large for a single release, suggest splitting. Document what's deferred and why as a comment. Adjust the candidate label if the target release changes. See `references/feature-exploration.md` → Rescoping. 5. **Feature Exploration checklist.** After creation, the Feature should pass the full checklist in `references/feature-exploration.md` before moving to Backlog. diff --git a/skills/rhdh-jira/references/to-issue.md b/skills/rhdh-jira/references/to-issue.md index 909a7f3..6ad7dca 100644 --- a/skills/rhdh-jira/references/to-issue.md +++ b/skills/rhdh-jira/references/to-issue.md @@ -4,6 +4,10 @@ Create a Story, Task, Bug, or Spike from conversation context. Automatically inf ## Workflow +### Step 0 — Grilling prerequisite + +Load `references/grill.md` → Grilling prerequisite and Validate before creating. Hard-require grilling before create. Also load `references/sizing.md` and `references/fields.md` before the grill. + ### Step 1 — Determine Context Two entry modes: @@ -21,8 +25,8 @@ Determine the issue type from the conversation context: |--------|------|---------|-------| | User-facing behavior change, UI, API contract | **Story** | RHIDP | Uses Story template | | Internal: CI, refactoring, tooling, tests, infra | **Task** | RHIDP | Uses Task template | -| Something is broken, regression, unexpected behavior | **Bug** | RHDHBUGS | Uses Bug template. **Do not include customer information — RHDHBUGS is public.** | -| Bug from a support case | **Bug** | RHDHSUPP | Uses Bug template. Support-originated — link to customer case. See `references/support.md`. | +| Something is broken, regression, unexpected behavior | **Bug** | RHDHBUGS | Uses Bug template. Prefer support key in summary/description; apply `RHDH-Customer` as a Jira label. RHDHBUGS is public — no customer-identifying detail in unprotected fields. See `references/fields.md`. | +| Bug from a support case | **Bug** | RHDHSUPP | Uses Bug template. Support-originated — link to support case key; apply `RHDH-Customer`. See `references/support.md` and `references/fields.md`. | | CVE, vulnerability, security advisory | **Vulnerability** | RHIDP | Requires Security component. Uses Story template and grill questions. | | "Investigate", "research", "spike", "explore", "POC", unknown scope | **Task** (spike) | RHIDP | Summary prefixed with `SPIKE:`. Requires time-boxed story points. | @@ -38,18 +42,22 @@ If the user disagrees, adjust. Additional disambiguation questions: Load the appropriate template and example from `assets/templates/` and `assets/examples/` (see `references/templates.md` for the mapping). -Synthesize: Draft as many template sections as possible from the conversation (and parent Epic if chained). If chained, pre-fill Background (link to parent Epic) and Dependencies. +Synthesize per `references/work-breakdown.md`: draft from conversation (and parent Epic if chained); do not re-ask settled Epic-level topics. If chained, pre-fill Background (link to parent Epic) and Dependencies / blockers. + +When drafting customer-origin context, one-line check against `references/fields.md`: support case key / persona / use case — no customer names. Present the draft: "Here's what I have. Review and tell me what's missing." -### Step 4 — Fill Gaps +### Step 4 — Fill Gaps + Challenge + +Invoke the installed `grilling` skill once covering Fill Gaps + Challenge (read its SKILL.md and follow it; `/grilling` if host supports slash-commands). Do not re-implement cadence in this skill. Apply domain challenges from `references/grill.md`. For unfilled sections, ask targeted questions based on the inferred type: **Story gaps:** 1. **User story** — "As a \ trying to \ I want \" -2. **Background** — context and motivation +2. **Background** — context and motivation (support case key / persona / use case — no customer names; see `references/fields.md`) 3. **Out of scope** — what's not included 4. **Approach** — general technical path, schemas, class definitions 5. **Dependencies** — linked Stories/Epics, QE/Doc impact @@ -82,20 +90,19 @@ For unfilled sections, ask targeted questions based on the inferred type: Skip questions the draft already answered. -### Step 5 — Challenge - -Follow the challenging behavior in `references/grill.md`. - -### Step 6 — Infer Fields +### Step 5 — Infer Fields Infer all Jira fields per `references/grill.md` Field Inference. If chained, inherit Priority, Team, and Component from parent Epic. Key fields: Priority, Component, Assignee, and Story Points (required for Spikes as time-box). -### Step 7 — Review +**Customer identity + labels:** Prefer support key in summary/description; apply `RHDH-Customer` as a Jira label for customer-origin work; put customer-identifying detail only in restricted-visibility comments. Never also apply `rhdh-customer`. See `references/fields.md`. -Render the filled template and inferred fields as a temporary markdown file for user review: +### Step 6 — Review + +Render the filled template and inferred fields as a temporary markdown file for user review. Use a portable temp path (`$TMPDIR` / `%TEMP%` / Python `tempfile`): ```bash -cat > /tmp/issue-review.md << 'EOF' +REVIEW=$(mktemp "${TMPDIR:-/tmp}/issue-review.XXXXXX.md") # Windows: %TEMP%\issue-review.md or tempfile +cat > "$REVIEW" << 'EOF' ## {Type}: {summary} ### Description @@ -113,11 +120,13 @@ EOF Present to the user: "Review the issue before creating. [approve / edit / cancel]" -### Step 8 — Duplicate Check +### Step 7 — Duplicate Check Run the pre-creation check from `references/duplicates.md`. Scope to the target project and type. -### Step 9 — Create Issue +### Step 8 — Create Issue + +Before create: re-check customer identity + label rules per `references/grill.md` → Validate before creating. Fill the appropriate template (`assets/templates/story.txt`, `task.txt`, or `bug.txt`) with grill results, then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`: @@ -171,7 +180,7 @@ curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \ Set Story Points via REST if acli fails — follow API preference order in SKILL.md. -### Step 10 — Comments +### Step 9 — Comments Follow the comment suggestion behavior from `references/grill.md` — proactively suggest decision trail, elaboration, and abandoned paths as comments. @@ -187,7 +196,7 @@ Follow the comment suggestion behavior from `references/grill.md` — proactivel ## Caveats -1. **Bugs go to RHDHBUGS.** Never create Bugs in RHIDP. RHDHBUGS is a public project — no customer information in the description. +1. **Bugs go to RHDHBUGS.** Never create Bugs in RHIDP. RHDHBUGS is a public project — prefer support key in summary/description; apply `RHDH-Customer` as a Jira label; no customer-identifying detail in unprotected fields. See `references/fields.md`. 2. **Spikes are Tasks, not a separate type.** Identified by the `SPIKE:` prefix in the summary. Always time-boxed. -3. **No further decomposition.** Stories, Tasks, and Bugs are leaf nodes. If the scope is too large for a single issue, suggest splitting into multiple issues or promoting to an Epic. +3. **No further decomposition.** Stories, Tasks, and Bugs are leaf nodes. If the scope is too large for a single issue, suggest splitting into multiple issues or promoting to an Epic — use tracer-bullet slices and blocking edges from `references/work-breakdown.md`, not horizontal layer splits. 4. **Done Checklist.** Stories include a Done Checklist in the template. Remind the user this is part of the definition of done. diff --git a/skills/rhdh-jira/references/work-breakdown.md b/skills/rhdh-jira/references/work-breakdown.md new file mode 100644 index 0000000..5dc86ba --- /dev/null +++ b/skills/rhdh-jira/references/work-breakdown.md @@ -0,0 +1,59 @@ +# Work Breakdown + +Vocabulary and rules for turning aligned conversation into Jira work under RHDH's Feature → Epic → Story/Task hierarchy. + +Load when decomposing a Feature into Epics, an Epic into Stories/Tasks, or when drafting create descriptions from conversation. + +## Synthesize, then grill gaps + +Once the conversation (and grilling) has aligned the problem, **synthesize** the draft from what you already know. Do not re-interview settled topics. + +- Prefer filling template sections from context first, then ask only for true gaps. +- When chained (Feature → Epic → Issue), carry parent scope/AC down; narrow the grill to *this* node's delivery slice. +- Capture **implementation decisions** and **testing decisions** that already landed in the chat as comments (or AC bullets) — don't leave them only in the agent's memory. +- Keep RHDH templates (Feature Exploration, Epic, Story/Task/Bug). Do not replace them with a generic PRD template. + +## Tracer bullets (vertical slices) + +Prefer **tracer bullet** children — narrow but **complete** paths that are demoable or verifiable on their own — over horizontal layers ("backend tickets" / "frontend tickets" / "docs-only" as a fake slice of the same behaviour). + +| Prefer | Avoid | +|--------|--------| +| "User can import a catalog entity via OCI and see it in the catalog" (Story) | "Add OCI API" + "Add UI" + "Add tests" as three tickets for one behaviour | +| Epic that delivers one team's end-to-end outcome for the Feature | Epic that is only a tech layer with no user-visible or ops-visible outcome | +| Prefactor / spike first when unknowns block slicing | Mixing investigation and delivery in one oversized Story | + +**RHDH Feature → Epic exception:** RHDH still usually creates Epics **per team** (Eng, Doc, …). Keep that process. Within a team's Epic → Stories/Tasks, apply tracer-bullet slicing. Across Epics, record **blocking edges** (which Epic must land before another can start). + +**Wide mechanical refactors** (rename, shared type change with huge blast radius) are the exception to vertical slicing — sequence as expand → migrate batches → contract, each as its own ticket/Epic AC with explicit blockers. + +## Blocking edges + +Every proposed child should declare what **blocks** it: + +- **None — can start immediately**, or +- Explicit parent/sibling keys or provisional titles ("blocked by Epic #1 SDK") + +Publish (create) in dependency order when practical: blockers first, so links and sprint planning reflect the real frontier. + +Use Jira links (`Blocks` / `is blocked by`) or clear Dependency section text when native linking is awkward cross-project. + +## Quiz before create + +Before creating a batch of children, present a numbered breakdown and ask: + +1. Granularity — too coarse / too fine? +2. Blocking edges — correct? +3. Merge or split any items? +4. (Feature → Epics) Overlap / consolidation — same as batch review in `to-epic.md` + +Do not create the batch until the user approves the breakdown. + +## Completion criteria (decomposition) + +Decomposition is done when: + +- Every child is a tracer bullet (or an explicit wide-refactor / spike exception) +- Every child has blocking edges stated +- User approved the batch table +- Customer-identity / `RHDH-Customer` rules from `fields.md` still hold on every new issue diff --git a/skills/rhdh-jira/scripts/setup.py b/skills/rhdh-jira/scripts/setup.py index f760e70..f07a715 100644 --- a/skills/rhdh-jira/scripts/setup.py +++ b/skills/rhdh-jira/scripts/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Verify acli installation and Jira authentication for RHDH projects.""" +"""Verify acli installation, Jira authentication, and grilling skill for RHDH.""" import argparse import json @@ -11,6 +11,10 @@ RHDH_PROJECTS = ["RHIDP", "RHDHPLAN", "RHDHBUGS", "RHDHSUPP"] JIRA_CONFIG_RELATIVE = Path(".config", "acli", "jira_config.yaml") +MINIMAL_GRILLING_INSTALL = "npx skills@latest add mattpocock/skills --skill grilling -g -y" +RECOMMENDED_GRILLING_INSTALL = "npx skills@latest add mattpocock/skills --all -g" +GRILLING_SKILL_RELATIVE = Path("grilling") / "SKILL.md" + def find_acli(): """Find acli binary on PATH.""" @@ -32,6 +36,40 @@ def find_acli(): return None +def grilling_search_paths(home=None, cwd=None): + """Return candidate paths for grilling/SKILL.md (user + project-local).""" + home = Path.home() if home is None else Path(home) + cwd = Path.cwd() if cwd is None else Path(cwd) + return [ + home / ".claude" / "skills" / GRILLING_SKILL_RELATIVE, + home / ".agents" / "skills" / GRILLING_SKILL_RELATIVE, + home / ".cursor" / "skills" / GRILLING_SKILL_RELATIVE, + cwd / ".claude" / "skills" / GRILLING_SKILL_RELATIVE, + cwd / ".agents" / "skills" / GRILLING_SKILL_RELATIVE, + cwd / ".cursor" / "skills" / GRILLING_SKILL_RELATIVE, + ] + + +def find_grilling(home=None, cwd=None): + """Return the first existing grilling/SKILL.md path, or None.""" + for path in grilling_search_paths(home=home, cwd=cwd): + if path.is_file(): + return path.resolve() + return None + + +def check_grilling(home=None, cwd=None): + """Build a results dict for grilling skill detection.""" + found = find_grilling(home=home, cwd=cwd) + return { + "grilling_found": found is not None, + "grilling_path": str(found) if found else None, + "minimal_install": MINIMAL_GRILLING_INSTALL, + "recommended_install": RECOMMENDED_GRILLING_INSTALL, + "overall": "pass" if found else "fail", + } + + def check_config(): """Check if Jira API token config exists.""" config_path = Path.home() / JIRA_CONFIG_RELATIVE @@ -125,13 +163,39 @@ def check_token_file(acli_path): return None, f"read error: {e}", warnings -def main(): +def _merge_grilling(results, home=None, cwd=None): + """Attach grilling detection fields to a full setup results dict.""" + grilling = check_grilling(home=home, cwd=cwd) + results["grilling_found"] = grilling["grilling_found"] + results["grilling_path"] = grilling["grilling_path"] + results["grilling_minimal_install"] = grilling["minimal_install"] + results["grilling_recommended_install"] = grilling["recommended_install"] + + +def main(argv=None): parser = argparse.ArgumentParser( - description="Verify acli installation and Jira authentication for RHDH." + description=( + "Verify acli installation and Jira authentication for RHDH. " + "Also detects Matt Pocock's grilling skill (required for create/grill paths)." + ) ) parser.add_argument("--json", action="store_true", help="Output results as JSON") parser.add_argument("--quick", action="store_true", help="Skip project accessibility check") - args = parser.parse_args() + parser.add_argument( + "--grilling-only", + action="store_true", + help=( + "Only check for the grilling skill (skip acli/auth). " + "Exit non-zero if grilling is missing. Use this from create/grill paths " + "so acli failures do not hide the grilling-specific prereq message." + ), + ) + args = parser.parse_args(argv) + + if args.grilling_only: + results = check_grilling() + _output_grilling(results, args.json) + sys.exit(0 if results["overall"] == "pass" else 1) results = { "acli_found": False, @@ -146,6 +210,10 @@ def main(): "connectivity_detail": None, "projects_accessible": [], "projects_inaccessible": [], + "grilling_found": False, + "grilling_path": None, + "grilling_minimal_install": MINIMAL_GRILLING_INSTALL, + "grilling_recommended_install": RECOMMENDED_GRILLING_INSTALL, "overall": "fail", } @@ -156,6 +224,7 @@ def main(): results["acli_path"] = acli_path else: results["connectivity_detail"] = "acli not found on PATH" + _merge_grilling(results) _output(results, args.json) sys.exit(1) @@ -180,6 +249,7 @@ def main(): results["connectivity_detail"] = detail if not ok: + _merge_grilling(results) _output(results, args.json) sys.exit(1) @@ -189,11 +259,49 @@ def main(): results["projects_accessible"] = accessible results["projects_inaccessible"] = [{"project": p, "error": e} for p, e in inaccessible] + # Step 6: grilling skill (informational in full mode — does not fail overall) + _merge_grilling(results) + results["overall"] = "pass" _output(results, args.json) sys.exit(0) +def _output_grilling(results, as_json): + """Print grilling-only results in JSON or human-readable format.""" + if as_json: + json.dump(results, sys.stdout, indent=2) + print() + return + + print("=" * 50) + print("RHDH Jira Grilling Check") + print("=" * 50) + print() + print("Hard prerequisite for create/grill paths: Matt Pocock's `grilling` skill.") + print("Used for interview cadence (one question at a time).") + print() + + if results["grilling_found"]: + print(f" [PASS] grilling found: {results['grilling_path']}") + else: + print(" [FAIL] grilling skill not found") + print(" Looked for grilling/SKILL.md under:") + print(" ~/.claude/skills/") + print(" ~/.agents/skills/") + print(" ~/.cursor/skills/") + print(" /.claude/skills/") + print(" /.agents/skills/") + print(" /.cursor/skills/") + print() + print(" Install (after user confirms — this script does not install):") + print(f" Minimal (gate installs this): {results['minimal_install']}") + print(f" Recommended (full Matt pack): {results['recommended_install']}") + + print() + print(f"Overall: {results['overall'].upper()}") + + def _output(results, as_json): """Print results in JSON or human-readable format.""" if as_json: @@ -211,6 +319,7 @@ def _output(results, as_json): else: print(" [FAIL] acli not found on PATH") print(" Install from: https://developer.atlassian.com/cloud/acli/") + _print_grilling_section(results) return # Config @@ -245,6 +354,7 @@ def _output(results, as_json): print(" [PASS] Jira connectivity verified") else: print(f" [FAIL] Jira connectivity failed: {results['connectivity_detail']}") + _print_grilling_section(results) return # Projects @@ -254,9 +364,26 @@ def _output(results, as_json): for item in results["projects_inaccessible"]: print(f" [WARN] {item['project']}: {item['error']}") + _print_grilling_section(results) + print() print(f"Overall: {results['overall'].upper()}") +def _print_grilling_section(results): + """Print grilling status in full setup output (warn if missing; does not fail overall).""" + if results.get("grilling_found"): + print(f" [PASS] grilling found: {results['grilling_path']}") + else: + print(" [WARN] grilling skill not found (required for to-feature / to-epic / to-issue)") + print(" Create/grill paths: python scripts/setup.py --grilling-only") + print( + f" Minimal: {results.get('grilling_minimal_install', MINIMAL_GRILLING_INSTALL)}" + ) + print( + f" Recommended: {results.get('grilling_recommended_install', RECOMMENDED_GRILLING_INSTALL)}" + ) + + if __name__ == "__main__": main() diff --git a/skills/skill-maker/SKILL.md b/skills/skill-maker/SKILL.md index 0bdbb1e..d2609e9 100644 --- a/skills/skill-maker/SKILL.md +++ b/skills/skill-maker/SKILL.md @@ -1,14 +1,32 @@ --- name: skill-maker -description: Create, audit, or consolidate agent skills following the Agent Skills open standard (agentskills.io). Interviews the user relentlessly about intent, scope, and edge cases before drafting. Covers SKILL.md structure, frontmatter, progressive disclosure, description optimization, script bundling, sub-command architecture, setup gates, context systems, and review. Use when the user wants to create a skill, write a skill, build a new skill, make a skill, draft a SKILL.md, or mentions "skill-maker". Also use when asked to review a skill, audit a SKILL.md, check why a skill never triggers, improve an existing skill, or fix a skill. Also use when asked to package expertise, workflows, or domain knowledge into a reusable skill. Also use when asked to consolidate skills, merge skills, combine skills, reduce skill count, or refactor multiple skills into one. +description: > + Relentless create-audit-consolidate workflow for Agent Skills (agentskills.io). + Use when creating a new skill or drafting a SKILL.md. Use when auditing or + reviewing why a skill never triggers. Use when consolidating overlapping + skills into fewer. Use when packaging expertise, workflows, or domain + knowledge into a reusable skill. --- - + # Create, Audit, or Consolidate Skills Create agent skills following the [Agent Skills open standard](https://agentskills.io/specification). +- Progressive disclosure: every-branch material inline; branch-specific behind pointers +- References are one level deep (no A → B → C chains) +- Descriptions under 1024 chars; SKILL.md body under 500 lines +- Surgical edits when fixing — don't rewrite unbroken sections +- Map quality issues to failure modes in `references/skill-quality.md` +- Command descriptions for audit/create/consolidate: `scripts/command-metadata.json` is the single source of truth + +**Create path grilling:** Create/interview hard-requires Matt Pocock's `grilling` skill. Full gate + invoke wording live in `references/create.md` (Phase 1). Audit and consolidate skip the gate unless you actually interview. + + + + + What do you need to do? 1. **Audit an existing skill** — Review, improve, or debug a SKILL.md @@ -16,447 +34,31 @@ What do you need to do? 3. **Consolidate skills** — Merge multiple skills into fewer **Wait for response before proceeding.** + | Response | Workflow | |----------|----------| -| 1, "audit", "review", "check", "fix", "improve" | Audit Workflow (Step 1–4 in this file) | -| 2, "create", "write", "build", "new", "draft" | Phases 1–5 (Interview → Draft → Description → Scripts → Review) in this file | -| 3, "consolidate", "merge", "combine" | `references/consolidation-guide.md` — return to Phase 5 for final checklist | +| 1, "audit", "review", "check", "fix", "improve" | `references/audit.md` | +| 2, "create", "write", "build", "new", "draft" | `references/create.md` | +| 3, "consolidate", "merge", "combine" | `references/consolidation-guide.md` — return to Phase 5 in `references/create.md` for final checklist | -## Audit Workflow - -Use this workflow when reviewing, improving, or debugging an existing skill. - -### Step 1: Locate and read the skill - -Read the full SKILL.md and list all files in the skill directory (`references/`, `scripts/`, `templates/`, `assets/`). - -### Step 2: Run the audit checklist - -Check each category. Note issues as you go. - -**Frontmatter:** - -- [ ] `name` matches the directory name, lowercase+hyphens, max 64 chars -- [ ] `description` is under 1024 chars, non-empty, third person -- [ ] `description` includes trigger phrases (not just a summary of what the skill does) -- [ ] `description` covers edge phrasings users would actually say - -**Structure:** - -- [ ] SKILL.md body is under 500 lines -- [ ] Essential principles are inline in SKILL.md (not only in a reference file) -- [ ] All referenced files exist (check every path in the SKILL.md) -- [ ] References are one level deep (no nested chains: A → B → C) - -**Content quality:** - -- [ ] No rigid ALWAYS/NEVER rules without reasoning (explain WHY) -- [ ] No explanations of things the agent already knows from training -- [ ] Steps are specific and verifiable (not "handle errors appropriately") -- [ ] Success criteria are observable and testable -- [ ] Examples use fake data where appropriate - -**Router pattern** (if applicable): - -- [ ] Intake question asks what the user wants before routing -- [ ] Router table maps commands to reference files -- [ ] All referenced workflow/reference files exist -- [ ] Essential principles are in SKILL.md, not only in sub-command references -- [ ] If skill has multiple semantic sections, consider XML tags for structure (see `references/xml-structure-guide.md`) - -**Scripts** (if present): - -- [ ] Scripts have shebangs, `--help`, and structured output -- [ ] No interactive prompts (all input via flags/env/stdin) -- [ ] Cross-platform paths (pathlib, no hardcoded separators) -- [ ] Error messages explain what went wrong and what to do - -Read `references/anti-patterns.md` for the full catalog of common failures. - -### Step 3: Generate the report - -Present findings grouped by severity: - -1. **Critical** — skill won't trigger or produces wrong output -2. **Important** — structural issues, missing files, spec violations -3. **Minor** — style, conciseness, optimization opportunities - -For each finding, state the issue, cite the specific line or section, and recommend a fix. - -### Step 4: Offer fixes - -Ask the user which findings to fix. Apply changes surgically — don't rewrite sections that aren't broken. Run the Phase 5 review checklist on the modified skill before finishing. - -## Phase 1: Interview - -Interview the user about every aspect of this skill until reaching shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. - -### Interview cadence - -Ask **one question at a time**. Wait for the answer before asking the next. Adapt follow-ups based on what you learn. Each question should provide clear benefit toward building a better skill — cut questions the codebase can answer for you. - -If a question can be answered by exploring the codebase, explore the codebase instead of asking. - -Focus areas, roughly in order: - -1. **Purpose and audience.** What task does this skill cover? What specific problem does it solve? What does the user do today without it? -2. **Scope boundaries.** What should this skill NOT do? What adjacent tasks belong to other skills? -3. **Input/output.** What does the user provide? What does the skill produce? Specific formats? -4. **Edge cases.** What goes wrong? Common mistakes? Gotchas for new users? -5. **Success criteria.** How do you know the skill worked correctly? -6. **What can be scripted?** Look for deterministic operations that should be code, not LLM instructions. Scripts are cheaper, faster, and more reliable. -7. **References needed?** Domain knowledge too large for SKILL.md that should live in separate files? -8. **Existing patterns.** Similar skills or workflows to draw from? Check the codebase. -9. **Platform constraints.** macOS, Windows, and Linux? Scripts must handle path separators, temp directories, and shell differences. -10. **External services and APIs.** Does the skill call external APIs or services? If yes, read `references/api-skill-patterns.md` — it covers credential handling, schema discovery, instance-specific values, and error placement. - -### Architecture decision tree - -After the interview questions above, decide the architecture. Most skills are simple — only escalate when the answers demand it. - -**Question 1: How many distinct things can a user want to do?** - -- One specific thing → **Simple skill** (single SKILL.md, under 200 lines) -- Multiple things with shared principles → continue to Q2 - -**Question 2: Is there shared domain knowledge across those operations?** - -- No, each operation is self-contained → **Simple skill** (or multiple separate simple skills) -- Yes, multiple operations share knowledge → **Router skill** (SKILL.md + `references/`) - -**Question 3: Does it cover a full lifecycle (build, debug, test, ship)?** - -- No → **Router skill** is sufficient -- Yes → **Domain expertise skill** (exhaustive references, full lifecycle workflows) - -| What you're building | Pattern | -|---|---| -| "A skill that commits with a conventional message" | Simple | -| "A skill that manages PRs — create, review, merge, close" | Router | -| "A skill for building and shipping macOS apps" | Domain expertise | -| "A skill that audits other skills" | Simple (upgrade to Router if it grows) | - -For Router and Domain expertise patterns, also ask: - -- **Does the skill need project-level context?** If every command needs the same background, design a context file pattern with a loader script. -- **Are there mandatory setup gates?** Steps that must pass before any work begins. Gates prevent generic output. -- **Does behavior vary by task type?** If so, design a register/mode system that classifies the task first, then loads different references. - -Read `references/architecture-patterns.md` for implementation details of each pattern. - -**Consolidation signal check:** If the interview reveals the new skill overlaps significantly with existing skills (shared scripts, cross-references, linear pipeline), consider consolidating instead of creating. Read `references/consolidation-guide.md` for the signals and workflow. - -Do not proceed to Phase 2 until the user confirms the scope is complete. - -## Phase 2: Draft the SKILL.md - -Write the skill following the spec. Read `references/spec-guide.md` for the full format reference before drafting. - -**Starter templates:** Use `templates/simple-skill.md` for single-purpose skills, `templates/router-skill.md` for multi-command skills using markdown headings, or `templates/router-skill-xml.md` for multi-command skills using XML structure. Copy the template as a starting point, then customize. - -### Frontmatter - -```yaml ---- -name: skill-name # lowercase, hyphens, max 64 chars -description: | # max 1024 chars — this is the ONLY triggering mechanism - What the skill does. Use when [specific triggers]. - Also use when [additional triggers]. ---- -``` - -The description must be slightly "pushy" — agents tend to undertrigger. Include both what the skill does AND specific phrases/contexts that should activate it. - -### Body structure - -Follow progressive disclosure — three loading levels: - -1. **Metadata** (~100 tokens): `name` and `description` loaded at startup for all skills -2. **Instructions** (< 500 lines): Full SKILL.md body loaded when skill activates -3. **Resources** (as needed): `references/`, `scripts/`, `assets/` loaded only when required - -Keep the SKILL.md body under 500 lines. If approaching this limit, split domain-specific content into `references/` files with clear pointers about when to read them. - -### Deduplication check - -Before writing domain knowledge into a new reference file, check if it already exists in another reference. Shared data (exit criteria, field mappings, workflow rules) must live in exactly one file. New references should point to the existing source — not embed a copy. - -Common trap: a new sub-command reference duplicates tables from an existing reference because it "needs them for context." Instead, add a one-line pointer: "Load `references/workflows.md` for exit criteria per status." - -**Exception: intentional duplication.** When two sub-commands need the same query pattern but referencing each other would create a transitive loading chain (A → B → C), duplicate the pattern and add a note: "Same query pattern as X.md Step N — duplicated here to avoid transitive loading." This is cheaper than forcing the agent to load an unrelated file. - -### Writing patterns - -- **Imperative form**: "Run the command" not "You should run the command" -- **Explain WHY, not just what**: Avoid rigid ALWAYS/NEVER rules without reasoning. Agents generalize from principles better than from rigid rules. Instead of "ALWAYS use pdfplumber. NEVER use PyPDF2," write "Use pdfplumber over PyPDF2 — it handles malformed PDFs more gracefully and preserves layout metadata needed for table extraction." Principles adapt to edge cases; rigid rules break. -- **Don't explain what the agent already knows**: Skip basic programming concepts, standard library usage, and well-known tool behavior. Only add context the agent doesn't have — project-specific conventions, non-obvious behavior, domain-specific gotchas. A 30-token code example beats a 150-token explanation of what a library is. -- **Output templates**: Define exact formats when the output structure matters -- **Concrete examples**: Show input → output for non-obvious workflows -- **Gotchas sections**: Common mistakes the agent should avoid -- **Checklists**: Multi-step workflows with validation gates -- **Conditional loading**: "Read `references/api-errors.md` if the API returns a non-200 status code" — not "see references/ for details" -- **Absolute bans**: When certain patterns are always wrong, use match-and-refuse lists. "If you're about to write X, stop and do Y instead." More effective than vague "be careful" guidance. -- **Avoid hardcoded thresholds**: Don't write arbitrary numbers as rules (e.g., "when you have 3+ sub-commands" or "if more than 5 issues") unless the threshold comes from a real constraint (API limit, spec requirement). Instead, describe the signal that triggers the behavior (e.g., "when you're copying the same text into another sub-command"). Hardcoded numbers feel authoritative but are usually guesses that don't generalize. - -Read `references/anti-patterns.md` during drafting to avoid known pitfalls. - -### XML structure (router and domain expertise skills) - -Agents parse XML tags more reliably than markdown headings when a skill has semantically distinct sections (principles, intake, routing, references). XML tags create unambiguous containers; markdown headings blend together in long prompts. - -Read `references/xml-structure-guide.md` for suggested patterns and anti-patterns. - -**When XML helps:** - -- Skills with an intake question + routing table + essential principles -- Skills where an agent needs to quickly locate a specific section -- Skills with inline workflows that need clear start/end boundaries - -**When markdown is enough:** - -- Simple skills with a single linear workflow -- Sequential instructional content (phases, steps) where order matters more than section lookup - -### Sub-command router (when applicable) - -For skills with multiple distinct operations, use a router table in SKILL.md. - -```xml - -## What would you like to do? - -1. **Craft a feature** — Build end-to-end -2. **Audit code** — Technical quality checks - -**Wait for response before proceeding.** - - - -| Response | Workflow | -|----------|----------| -| 1, "craft", "build" | `references/craft.md` | -| 2, "audit", "check" | `references/audit.md` | - -``` - -Back the router with a `scripts/command-metadata.json` as the single source of truth: - -```json -{ - "craft": { - "description": "Full build flow. Use when building a new feature end-to-end.", - "argumentHint": "[feature description]" - } -} -``` - -### Setup gates (when applicable) - -Non-negotiable checks before any file edits. Gates prevent generic output from missing context. - -```markdown -## Setup (non-optional) - -| Gate | Required check | If fail | -|---|---|---| -| Context | Project config loaded via `python scripts/load_context.py` | Run the loader first | -| Config | Config file exists and is valid | Run `skill-name setup` | -| Command | Sub-command reference is loaded | Load the reference | -| Mutation | All gates above pass | Do not edit project files | -``` - -### Register/mode system (when applicable) - -When behavior varies by task type, classify first, then load different references: - -```markdown -## Register - -Every task is **library** (published, API-stable) or **application** (internal, can break). -Identify before acting. Load the matching reference: [references/library.md] or [references/application.md]. -``` - -### Capability-gating - -Steps that depend on optional environment capabilities (browser automation, specific CLI tools) must degrade gracefully: - -```markdown -### Automated Scan (Capability-Gated) - -Run the automated scanner when ALL of these are true: -- The target files exist and are readable -- The required CLI tool is installed - -If unavailable, state in one line that the step is skipped and why. Do not ask the user to install tooling. -``` - -### Structured artifacts as handoffs - -When one command produces output that another consumes, define the artifact structure explicitly. The producing command's reference defines the format; the consuming command's reference says what it expects: - -```markdown -### Plan Structure - -**1. Summary** (2-3 sentences) -**2. Primary Goal** -**3. Approach** -... -``` - -### Self-critique loops - -For build/implementation commands, mandate inspect-and-fix passes with explicit exit bars: - -```markdown -### Critique and fix loop - -After the first pass, write a short self-critique and patch. Repeat until no material issues remain: -1. Does it match the requirements? -2. Does it pass the [quality test]? -3. Check every expected scenario. -4. Check edge cases. - -The exit bar is not "it works." It is: [explicit quality threshold]. -``` - -## Phase 3: Description Optimization - -The description is the only thing agents see at startup. Read `references/description-guide.md` for the full optimization process. - -Quick validation: - -1. Write 5 should-trigger queries (different phrasings, including ones that don't name the skill directly) -2. Write 5 should-not-trigger queries (near-misses that share keywords but need different skills) -3. Check: would the description correctly distinguish these? -4. Revise if needed — broaden for missed triggers, narrow for false triggers -5. Verify under 1024 characters - -For skills with sub-commands, the main description covers the skill broadly. Each sub-command's description in `command-metadata.json` is optimized separately for auto-trigger keyword matching. - -## Phase 4: Scripts - -Read `references/scripts-guide.md` for the full guide. - -**Bias toward scripts.** Every deterministic operation should be a script, not an instruction. Scripts are cheaper (no LLM tokens), faster (no reasoning), and more reliable (no hallucination). - -For each piece of the skill's workflow, ask: "Could a script do this?" If yes, write the script. - -**Should be scripts:** - -- Validation (input format, required fields, schema compliance) -- File generation from templates -- Data extraction and transformation -- API calls with structured responses -- Setup and environment checks -- Output formatting -- Context loading (read project files, resolve paths, return JSON) -- Pin/unpin shortcuts (create/remove command aliases) -- Cleanup (remove deprecated files after skill updates) - -**Should stay as instructions:** - -- Deciding between architectural approaches -- Reviewing code for quality or style -- Explaining tradeoffs to the user -- Creative writing or design decisions -- Interview/discovery conversations - -Key patterns: - -- **Python without dependencies**: stdlib only, `argparse` for CLI parsing -- **Python with dependencies**: PEP 723 inline metadata with `uv run` -- **All scripts**: Structured output (JSON when piped), clear exit codes, descriptive `--help` - -### Context loader pattern - -For skills that need project-level context, write a loader script: - -The script should follow all standard patterns: `argparse` with `--help`, structured JSON output (pretty when interactive, compact when piped), clear exit codes (0 = found, 1 = missing), `pathlib` for cross-platform paths, and stdlib-only imports. See the "Context File System" section in `references/architecture-patterns.md` for a skeleton. - -The SKILL.md references it: "Load context via `python scripts/load_context.py`. Consume the full JSON output. Never pipe through `head`, `tail`, or `grep`." - -## Phase 5: Review - -Before presenting the final skill, verify against this checklist: - -### Basics - -- [ ] `name` is lowercase, hyphens only, max 64 chars -- [ ] `description` is under 1024 chars and includes trigger phrases -- [ ] `description` is slightly pushy — covers edge phrasings that should activate the skill -- [ ] SKILL.md body is under 500 lines -- [ ] Instructions use imperative form - -### Architecture (if applicable) - -- [ ] Sub-commands have a router table with clear routing rules -- [ ] `command-metadata.json` is the single source of truth for command descriptions -- [ ] Setup gates are defined with fail actions for each gate -- [ ] Register/mode system classifies before loading references -- [ ] Capability-gated steps degrade gracefully with one-line skip reasons -- [ ] Router/domain skills with distinct sections (intake, routing, principles) consider XML tags for clarity (`references/xml-structure-guide.md`) - -### References - -- [ ] Domain knowledge split into `references/` with clear "when to read" pointers -- [ ] Each reference is self-contained — no transitive loading (see `spec-guide.md` → Reference Architecture) -- [ ] Reference loading is conditional, not eager ("Read X if Y happens") -- [ ] Shared concerns (auth, config) extracted into their own reference, not embedded in a consumer -- [ ] Error handling lives in the reference for the tool that produces the error -- [ ] Multi-approach skills include a decision table routing to the correct reference -- [ ] No browser-only tools referenced (Postman, API consoles, OAuth login pages) - -### Scripts - -- [ ] Scripts (if any) have shebangs, structured output, and `--help` -- [ ] Context loader returns JSON, handles missing files, resolves fallback paths -- [ ] Scripts are cross-platform (pathlib, tempfile, no hardcoded paths) -- [ ] Scripts are idempotent — safe to re-run - -### API/Service Skills (if applicable) - -- [ ] Credential files are never read into context — passed via shell substitution only -- [ ] Credential setup is single-sourced in its own reference file -- [ ] Capability gate checks for credentials before attempting API calls -- [ ] API schema discovery is documented (OpenAPI download, GraphQL introspection, or live endpoints) -- [ ] API examples have been validated against the live endpoint -- [ ] Instance-specific values include programmatic discovery methods - -### Consolidation (if merging existing skills) - -- [ ] No references to old skill names anywhere in the project (`grep -rn` the entire repo) -- [ ] Router intake menus are sequentially numbered (no gaps from removed items) -- [ ] Script docstrings and `--help` text reference the new skill name, not the old ones -- [ ] Reference paths resolve correctly from each file's location (no `references/references/` nesting) -- [ ] All example files from old skills are represented in the consolidated examples -- [ ] Scripts in the same skill use consistent patterns (NO_COLOR, shell flags, TTY checks, exit codes) -- [ ] README, ADRs, and other docs updated to reflect new skill structure -- [ ] New description covers all trigger phrases from all old skills' descriptions - -### Quality - -- [ ] No time-sensitive information (URLs to specific versions, dates that will go stale) -- [ ] Examples use fake data where possible (emails, names, tokens) — see `spec-guide.md` → Fake Data in Examples -- [ ] Consistent terminology throughout -- [ ] Concrete examples included for non-obvious workflows -- [ ] Absolute bans defined for patterns that are always wrong -- [ ] Self-critique loops defined for build/implementation commands with explicit exit bars - ## Reference Index | Reference | Load when... | |-----------|-------------| +| `references/audit.md` | Audit branch — review, improve, or debug an existing skill | +| `references/create.md` | Create branch — interview through review (Phases 1–5) | | `references/spec-guide.md` | Drafting a SKILL.md (Phase 2) — full format reference | | `references/description-guide.md` | Optimizing the description (Phase 3) | | `references/scripts-guide.md` | Writing scripts (Phase 4) | +| `references/skill-quality.md` | Drafting, auditing, or reviewing — predictability vocabulary and failure modes | | `references/anti-patterns.md` | Drafting or auditing — common failures to avoid | | `references/architecture-patterns.md` | Choosing between simple, router, and domain expertise patterns | | `references/api-skill-patterns.md` | Skill calls external APIs or services | diff --git a/skills/skill-maker/references/anti-patterns.md b/skills/skill-maker/references/anti-patterns.md index 0d74cd8..ede157d 100644 --- a/skills/skill-maker/references/anti-patterns.md +++ b/skills/skill-maker/references/anti-patterns.md @@ -2,6 +2,8 @@ Common failures and how to fix them. Read this during Phase 2 (drafting) to avoid known pitfalls. +For the shared quality vocabulary (predictability, progressive disclosure, completion criteria, failure modes like sediment/sprawl/no-op/negation), see `skill-quality.md`. + ## Discovery Failures ### Context Selection Omission (CSO) diff --git a/skills/skill-maker/references/api-skill-patterns.md b/skills/skill-maker/references/api-skill-patterns.md index 677e40e..34e81ea 100644 --- a/skills/skill-maker/references/api-skill-patterns.md +++ b/skills/skill-maker/references/api-skill-patterns.md @@ -2,7 +2,7 @@ Lessons learned from building skills that wrap CLIs, REST APIs, and GraphQL APIs. Read this when the skill interacts with external services or APIs. -For general reference architecture patterns (transitive loading, error placement, decision tables, agent-only audience), see `references/spec-guide.md` → Reference Architecture. +For general reference architecture patterns (transitive loading, error placement, decision tables, agent-only audience), see `spec-guide.md` → Reference Architecture. ## Credential handling diff --git a/skills/skill-maker/references/architecture-patterns.md b/skills/skill-maker/references/architecture-patterns.md index 501969b..7ee286a 100644 --- a/skills/skill-maker/references/architecture-patterns.md +++ b/skills/skill-maker/references/architecture-patterns.md @@ -135,6 +135,8 @@ Define gates as a table with required check and fail action: | Mutation | All gates above pass | Do not edit project files | ``` +`scripts/load_context.py` above is **example only** — name the loader to match the skill you are building. + The **Mutation** gate is always last. No file edits until every other gate passes. ### Preflight declaration @@ -206,7 +208,7 @@ The names should match the domain. A design skill uses `PRODUCT.md` and `DESIGN. ### Loader script -Write a script that finds, reads, and returns context as JSON: +Write a script that finds, reads, and returns context as JSON. The `load_context` / `load_context.py` names below are **example only**. ```python #!/usr/bin/env python3 diff --git a/skills/skill-maker/references/audit.md b/skills/skill-maker/references/audit.md new file mode 100644 index 0000000..0ec0b08 --- /dev/null +++ b/skills/skill-maker/references/audit.md @@ -0,0 +1,72 @@ +# Audit Workflow + +Use this workflow when reviewing, improving, or debugging an existing skill. + +Command descriptions for audit/create/consolidate: `scripts/command-metadata.json` is the single source of truth. + +## Step 1: Locate and read the skill + +Read the full SKILL.md and list all files in the skill directory (`references/`, `scripts/`, `templates/`, `assets/`). + +## Step 2: Run the audit checklist + +Check each category. Note issues as you go. Map structural/content findings to failure modes in `references/skill-quality.md` (premature completion, duplication, sediment, sprawl, no-op, negation) when diagnosing why a skill misfires or bloats. + +**Frontmatter:** + +- [ ] `name` matches the directory name, lowercase+hyphens, max 64 chars +- [ ] `description` is under 1024 chars, non-empty, third person +- [ ] `description` includes trigger phrases (not just a summary of what the skill does) +- [ ] `description` covers edge phrasings users would actually say +- [ ] `description` front-loads a leading word / one trigger per branch (see `references/skill-quality.md`) + +**Structure:** + +- [ ] SKILL.md body is under 500 lines +- [ ] Essential principles are inline in SKILL.md (not only in a reference file) +- [ ] All referenced files exist (check every path in the SKILL.md) +- [ ] References are one level deep (no nested chains: A → B → C) +- [ ] Context pointers name *when* to load (not vague "see references/") +- [ ] Progressive disclosure: every-branch material inline; branch-specific behind pointers + +**Content quality:** + +- [ ] No rigid ALWAYS/NEVER rules without reasoning (explain WHY) +- [ ] No explanations of things the agent already knows from training (no-ops) +- [ ] Steps are specific and verifiable (not "handle errors appropriately") +- [ ] Success criteria / completion criteria are observable and testable +- [ ] Examples use fake data where appropriate +- [ ] No negation-only steering without a positive target behaviour + +**Router pattern** (if applicable): + +- [ ] Intake question asks what the user wants before routing +- [ ] Router table maps commands to reference files +- [ ] All referenced workflow/reference files exist +- [ ] Essential principles are in SKILL.md, not only in sub-command references +- [ ] If skill has multiple semantic sections, consider XML tags for structure (see `references/xml-structure-guide.md`) + +**Scripts** (if present): + +- [ ] Scripts have shebangs, `--help`, and structured output +- [ ] No interactive prompts (all input via flags/env/stdin) +- [ ] Cross-platform paths (pathlib, no hardcoded separators) +- [ ] Error messages explain what went wrong and what to do + +Read `references/anti-patterns.md` for the full catalog of common failures. + +## Step 3: Generate the report + +Present findings grouped by severity: + +1. **Critical** — skill won't trigger or produces wrong output +2. **Important** — structural issues, missing files, spec violations +3. **Minor** — style, conciseness, optimization opportunities + +For each finding, state the issue, cite the specific line or section, and recommend a fix. + +## Step 4: Offer fixes + +Ask the user which findings to fix. Apply changes surgically — don't rewrite sections that aren't broken. Before finishing, verify modified skills against the Phase 5 review checklist in `references/create.md` (Basics through Quality). + +Audit does **not** require the `grilling` skill unless you actually run an interview/grill (e.g. clarifying ambiguous scope with the user). For a pure read-and-report audit, skip the grilling setup gate. diff --git a/skills/skill-maker/references/consolidation-guide.md b/skills/skill-maker/references/consolidation-guide.md index 67c995e..8ae9648 100644 --- a/skills/skill-maker/references/consolidation-guide.md +++ b/skills/skill-maker/references/consolidation-guide.md @@ -107,7 +107,7 @@ Reference files use relative paths. After moving files, paths break in subtle wa ### Step 7: Review -Run the standard Phase 5 review checklist from SKILL.md, plus these consolidation-specific checks: +Run the standard Phase 5 review checklist from `references/create.md`, plus these consolidation-specific checks: - [ ] No references to old skill names anywhere in the project - [ ] Router intake menu is sequentially numbered (no gaps) diff --git a/skills/skill-maker/references/create.md b/skills/skill-maker/references/create.md new file mode 100644 index 0000000..275f644 --- /dev/null +++ b/skills/skill-maker/references/create.md @@ -0,0 +1,375 @@ +# Create Workflow (Phases 1–5) + +Interview, draft, optimize, script, and review a new skill from scratch. + +Command descriptions for audit/create/consolidate: `scripts/command-metadata.json` is the single source of truth. + +## Phase 1: Interview + +### Grilling prerequisite (hard gate) + +Before interviewing on the create path, verify Matt Pocock's `grilling` skill is installed: + +1. Run `python scripts/setup.py --json` (from this skill's directory) and check `grilling_found` / `overall`. +2. If `overall` is `fail`: tell the user that `grilling` is a **hard prerequisite** for create/interview. Recommend the full Matt pack (`recommended_install` from the setup output). Ask for confirmation before installing. +3. After confirm, run the minimal install command from setup output (`minimal_install`) — typically `npx skills@latest add mattpocock/skills --skill grilling -g -y`. Do **not** auto-install without confirmation. The setup script detects only; this skill owns the confirm+install dialogue. +4. Re-run `python scripts/setup.py --json`. Continue only when `overall` is `pass`. + +### Interview cadence + +Invoke the installed `grilling` skill (read its SKILL.md and follow it). Do not paraphrase its cadence rules. If the host supports skill slash-commands, `/grilling` is equivalent. + +Use grilling to walk the focus areas and architecture decision tree below. If a fact can be answered by exploring the codebase, explore instead of asking. + +Focus areas, roughly in order: + +1. **Purpose and audience.** What task does this skill cover? What specific problem does it solve? What does the user do today without it? +2. **Scope boundaries.** What should this skill NOT do? What adjacent tasks belong to other skills? +3. **Input/output.** What does the user provide? What does the skill produce? Specific formats? +4. **Edge cases.** What goes wrong? Common mistakes? Gotchas for new users? +5. **Success criteria.** How do you know the skill worked correctly? +6. **What can be scripted?** Look for deterministic operations that should be code, not LLM instructions. Scripts are cheaper, faster, and more reliable. +7. **References needed?** Domain knowledge too large for SKILL.md that should live in separate files? +8. **Existing patterns.** Similar skills or workflows to draw from? Check the codebase. +9. **Platform constraints.** macOS, Windows, and Linux? Scripts must handle path separators, temp directories, and shell differences. +10. **External services and APIs.** Does the skill call external APIs or services? If yes, read `references/api-skill-patterns.md` — it covers credential handling, schema discovery, instance-specific values, and error placement. + +### Architecture decision tree + +After the interview questions above, decide the architecture. Most skills are simple — only escalate when the answers demand it. + +**Question 1: How many distinct things can a user want to do?** + +- One specific thing → **Simple skill** (single SKILL.md, under 200 lines) +- Multiple things with shared principles → continue to Q2 + +**Question 2: Is there shared domain knowledge across those operations?** + +- No, each operation is self-contained → **Simple skill** (or multiple separate simple skills) +- Yes, multiple operations share knowledge → **Router skill** (SKILL.md + `references/`) + +**Question 3: Does it cover a full lifecycle (build, debug, test, ship)?** + +- No → **Router skill** is sufficient +- Yes → **Domain expertise skill** (exhaustive references, full lifecycle workflows) + +| What you're building | Pattern | +|---|---| +| "A skill that commits with a conventional message" | Simple | +| "A skill that manages PRs — create, review, merge, close" | Router | +| "A skill for building and shipping macOS apps" | Domain expertise | +| "A skill that audits other skills" | Simple (upgrade to Router if it grows) | + +For Router and Domain expertise patterns, also ask: + +- **Does the skill need project-level context?** If every command needs the same background, design a context file pattern with a loader script. +- **Are there mandatory setup gates?** Steps that must pass before any work begins. Gates prevent generic output. +- **Does behavior vary by task type?** If so, design a register/mode system that classifies the task first, then loads different references. + +Read `references/architecture-patterns.md` for implementation details of each pattern. + +**Consolidation signal check:** If the interview reveals the new skill overlaps significantly with existing skills (shared scripts, cross-references, linear pipeline), consider consolidating instead of creating. Read `references/consolidation-guide.md` for the signals and workflow. + +Do not proceed to Phase 2 until the user confirms the scope is complete. + +## Phase 2: Draft the SKILL.md + +Write the skill following the spec. Read `references/spec-guide.md` for the full format reference before drafting. Read `references/skill-quality.md` before drafting (predictability via information hierarchy, checkable completion criteria, strong context pointers, pruning) and again during Phase 5 Quality. + +**Starter templates:** Use `templates/simple-skill.md` for single-purpose skills, `templates/router-skill.md` for multi-command skills using markdown headings, or `templates/router-skill-xml.md` for multi-command skills using XML structure. Copy the template as a starting point, then customize. + +### Frontmatter + +```yaml +--- +name: skill-name # lowercase, hyphens, max 64 chars +description: | # max 1024 chars — this is the ONLY triggering mechanism + What the skill does. Use when [specific triggers]. + Also use when [additional triggers]. +--- +``` + +The description must be slightly "pushy" — agents tend to undertrigger. Include both what the skill does AND specific phrases/contexts that should activate it. + +### Body structure + +Follow progressive disclosure — three loading levels: + +1. **Metadata** (~100 tokens): `name` and `description` loaded at startup for all skills +2. **Instructions** (< 500 lines): Full SKILL.md body loaded when skill activates +3. **Resources** (as needed): `references/`, `scripts/`, `assets/` loaded only when required + +Keep the SKILL.md body under 500 lines. If approaching this limit, split domain-specific content into `references/` files with clear pointers about when to read them. + +### Deduplication check + +Before writing domain knowledge into a new reference file, check if it already exists in another reference. Shared data (exit criteria, field mappings, workflow rules) must live in exactly one file. New references should point to the existing source — not embed a copy. + +Common trap: a new sub-command reference duplicates tables from an existing reference because it "needs them for context." Instead, add a one-line pointer: "Load `references/workflows.md` for exit criteria per status." + +**Exception: intentional duplication.** When two sub-commands need the same query pattern but referencing each other would create a transitive loading chain (A → B → C), duplicate the pattern and add a note: "Same query pattern as X.md Step N — duplicated here to avoid transitive loading." This is cheaper than forcing the agent to load an unrelated file. + +### Writing patterns + +- **Imperative form**: "Run the command" not "You should run the command" +- **Explain WHY, not just what**: Avoid rigid ALWAYS/NEVER rules without reasoning. Agents generalize from principles better than from rigid rules. Instead of "ALWAYS use pdfplumber. NEVER use PyPDF2," write "Use pdfplumber over PyPDF2 — it handles malformed PDFs more gracefully and preserves layout metadata needed for table extraction." Principles adapt to edge cases; rigid rules break. +- **Don't explain what the agent already knows**: Skip basic programming concepts, standard library usage, and well-known tool behavior. Only add context the agent doesn't have — project-specific conventions, non-obvious behavior, domain-specific gotchas. A 30-token code example beats a 150-token explanation of what a library is. +- **Output templates**: Define exact formats when the output structure matters +- **Concrete examples**: Show input → output for non-obvious workflows +- **Gotchas sections**: Common mistakes the agent should avoid +- **Checklists**: Multi-step workflows with validation gates +- **Conditional loading**: "Read `references/api-errors.md` if the API returns a non-200 status code" — not "see references/ for details" +- **Absolute bans**: When certain patterns are always wrong, use match-and-refuse lists. "If you're about to write X, stop and do Y instead." More effective than vague "be careful" guidance. +- **Avoid hardcoded thresholds**: Don't write arbitrary numbers as rules (e.g., "when you have 3+ sub-commands" or "if more than 5 issues") unless the threshold comes from a real constraint (API limit, spec requirement). Instead, describe the signal that triggers the behavior (e.g., "when you're copying the same text into another sub-command"). Hardcoded numbers feel authoritative but are usually guesses that don't generalize. + +Read `references/anti-patterns.md` during drafting to avoid known pitfalls. + +### XML structure (router and domain expertise skills) + +Agents parse XML tags more reliably than markdown headings when a skill has semantically distinct sections (principles, intake, routing, references). XML tags create unambiguous containers; markdown headings blend together in long prompts. + +Read `references/xml-structure-guide.md` for suggested patterns and anti-patterns. + +**When XML helps:** + +- Skills with an intake question + routing table + essential principles +- Skills where an agent needs to quickly locate a specific section +- Skills with inline workflows that need clear start/end boundaries + +**When markdown is enough:** + +- Simple skills with a single linear workflow +- Sequential instructional content (phases, steps) where order matters more than section lookup + +### Sub-command router (when applicable) + +For skills with multiple distinct operations, use a router table in SKILL.md. + +```xml + +## What would you like to do? + +1. **Craft a feature** — Build end-to-end +2. **Audit code** — Technical quality checks + +**Wait for response before proceeding.** + + + +| Response | Workflow | +|----------|----------| +| 1, "craft", "build" | `references/craft.md` | +| 2, "audit", "check" | `references/audit.md` | + +``` + +Paths like `references/craft.md` above are **example only** — substitute real command reference names for the skill you are building. + +Back the router with a `scripts/command-metadata.json` as the single source of truth: + +```json +{ + "craft": { + "description": "Full build flow. Use when building a new feature end-to-end.", + "argumentHint": "[feature description]" + } +} +``` + +### Setup gates (when applicable) + +Non-negotiable checks before any file edits. Gates prevent generic output from missing context. + +```markdown +## Setup (non-optional) + +| Gate | Required check | If fail | +|---|---|---| +| Context | Project config loaded via `python scripts/load_context.py` | Run the loader first | +| Config | Config file exists and is valid | Run `skill-name setup` | +| Command | Sub-command reference is loaded | Load the reference | +| Mutation | All gates above pass | Do not edit project files | +``` + +`scripts/load_context.py` in the table above is **example only** — name the loader to match the skill you are building. + +### Register/mode system (when applicable) + +When behavior varies by task type, classify first, then load different references: + +```markdown +## Register + +Every task is **library** (published, API-stable) or **application** (internal, can break). +Identify before acting. Load the matching reference: [references/library.md] or [references/application.md]. +``` + +### Capability-gating + +Steps that depend on optional environment capabilities (browser automation, specific CLI tools) must degrade gracefully: + +```markdown +### Automated Scan (Capability-Gated) + +Run the automated scanner when ALL of these are true: +- The target files exist and are readable +- The required CLI tool is installed + +If unavailable, state in one line that the step is skipped and why. Do not ask the user to install tooling. +``` + +### Structured artifacts as handoffs + +When one command produces output that another consumes, define the artifact structure explicitly. The producing command's reference defines the format; the consuming command's reference says what it expects: + +```markdown +### Plan Structure + +**1. Summary** (2-3 sentences) +**2. Primary Goal** +**3. Approach** +... +``` + +### Self-critique loops + +For build/implementation commands, mandate inspect-and-fix passes with explicit exit bars: + +```markdown +### Critique and fix loop + +After the first pass, write a short self-critique and patch. Repeat until no material issues remain: +1. Does it match the requirements? +2. Does it pass the [quality test]? +3. Check every expected scenario. +4. Check edge cases. + +The exit bar is not "it works." It is: [explicit quality threshold]. +``` + +## Phase 3: Description Optimization + +The description is the only thing agents see at startup. Read `references/description-guide.md` for the full optimization process. + +Quick validation: + +1. Write should-trigger queries — at least enough to cover each branch and near-miss; prefer 8–10 per `references/description-guide.md`, minimum cover each branch +2. Write should-not-trigger queries — near-misses that share keywords but need different skills (same coverage bar as should-trigger) +3. Check: would the description correctly distinguish these? +4. Revise if needed — broaden for missed triggers, narrow for false triggers +5. Verify under 1024 characters + +For skills with sub-commands, the main description covers the skill broadly. Each sub-command's description in `command-metadata.json` is optimized separately for auto-trigger keyword matching. + +## Phase 4: Scripts + +Read `references/scripts-guide.md` for the full guide. + +**Bias toward scripts.** Every deterministic operation should be a script, not an instruction. Scripts are cheaper (no LLM tokens), faster (no reasoning), and more reliable (no hallucination). + +For each piece of the skill's workflow, ask: "Could a script do this?" If yes, write the script. + +**Should be scripts:** + +- Validation (input format, required fields, schema compliance) +- File generation from templates +- Data extraction and transformation +- API calls with structured responses +- Setup and environment checks +- Output formatting +- Context loading (read project files, resolve paths, return JSON) +- Pin/unpin shortcuts (create/remove command aliases) +- Cleanup (remove deprecated files after skill updates) + +**Should stay as instructions:** + +- Deciding between architectural approaches +- Reviewing code for quality or style +- Explaining tradeoffs to the user +- Creative writing or design decisions +- Interview/discovery conversations + +Key patterns: + +- **Python without dependencies**: stdlib only, `argparse` for CLI parsing +- **Python with dependencies**: PEP 723 inline metadata with `uv run` +- **All scripts**: Structured output (JSON when piped), clear exit codes, descriptive `--help` + +### Context loader pattern + +For skills that need project-level context, write a loader script: + +The script should follow all standard patterns: `argparse` with `--help`, structured JSON output (pretty when interactive, compact when piped), clear exit codes (0 = found, 1 = missing), `pathlib` for cross-platform paths, and stdlib-only imports. See the "Context File System" section in `references/architecture-patterns.md` for a skeleton. + +The SKILL.md references it — for example only: "Load context via `python scripts/load_context.py`. Consume the full JSON output. Never pipe through `head`, `tail`, or `grep`." Rename the script to match the skill. + +## Phase 5: Review + +Before presenting the final skill, verify against this checklist: + +### Basics + +- [ ] `name` is lowercase, hyphens only, max 64 chars +- [ ] `description` is under 1024 chars and includes trigger phrases +- [ ] `description` is slightly pushy — covers edge phrasings that should activate the skill +- [ ] SKILL.md body is under 500 lines +- [ ] Instructions use imperative form + +### Architecture (if applicable) + +- [ ] Sub-commands have a router table with clear routing rules +- [ ] `command-metadata.json` is the single source of truth for command descriptions +- [ ] Setup gates are defined with fail actions for each gate +- [ ] Register/mode system classifies before loading references +- [ ] Capability-gated steps degrade gracefully with one-line skip reasons +- [ ] Router/domain skills with distinct sections (intake, routing, principles) consider XML tags for clarity (`references/xml-structure-guide.md`) + +### References + +- [ ] Domain knowledge split into `references/` with clear "when to read" pointers +- [ ] Each reference is self-contained — no transitive loading (see `spec-guide.md` → Reference Architecture) +- [ ] Reference loading is conditional, not eager ("Read X if Y happens") +- [ ] Shared concerns (auth, config) extracted into their own reference, not embedded in a consumer +- [ ] Error handling lives in the reference for the tool that produces the error +- [ ] Multi-approach skills include a decision table routing to the correct reference +- [ ] No browser-only tools referenced (Postman, API consoles, OAuth login pages) + +### Scripts + +- [ ] Scripts (if any) have shebangs, structured output, and `--help` +- [ ] Context loader returns JSON, handles missing files, resolves fallback paths +- [ ] Scripts are cross-platform (pathlib, tempfile, no hardcoded paths) +- [ ] Scripts are idempotent — safe to re-run + +### API/Service Skills (if applicable) + +- [ ] Credential files are never read into context — passed via shell substitution only +- [ ] Credential setup is single-sourced in its own reference file +- [ ] Capability gate checks for credentials before attempting API calls +- [ ] API schema discovery is documented (OpenAPI download, GraphQL introspection, or live endpoints) +- [ ] API examples have been validated against the live endpoint +- [ ] Instance-specific values include programmatic discovery methods + +### Consolidation (if merging existing skills) + +- [ ] No references to old skill names anywhere in the project (`grep -rn` the entire repo) +- [ ] Router intake menus are sequentially numbered (no gaps from removed items) +- [ ] Script docstrings and `--help` text reference the new skill name, not the old ones +- [ ] Reference paths resolve correctly from each file's location (no `references/references/` nesting) +- [ ] All example files from old skills are represented in the consolidated examples +- [ ] Scripts in the same skill use consistent patterns (NO_COLOR, shell flags, TTY checks, exit codes) +- [ ] README, ADRs, and other docs updated to reflect new skill structure +- [ ] New description covers all trigger phrases from all old skills' descriptions + +### Quality + +Read `references/skill-quality.md` again during this Quality pass (same file as before drafting). + +- [ ] No time-sensitive information (URLs to specific versions, dates that will go stale) +- [ ] Examples use fake data where possible (emails, names, tokens) — see `spec-guide.md` → Fake Data in Examples +- [ ] Consistent terminology throughout +- [ ] Concrete examples included for non-obvious workflows +- [ ] Absolute bans defined for patterns that are always wrong (pair with positive target — avoid negation-only) +- [ ] Self-critique loops defined for build/implementation commands with explicit exit bars +- [ ] Steps have checkable completion criteria; no obvious premature-completion traps +- [ ] No duplication / sediment / no-ops left after pruning (see `references/skill-quality.md`) diff --git a/skills/skill-maker/references/description-guide.md b/skills/skill-maker/references/description-guide.md index e66a99b..c0572d0 100644 --- a/skills/skill-maker/references/description-guide.md +++ b/skills/skill-maker/references/description-guide.md @@ -10,6 +10,8 @@ Key insight: agents only consult skills for tasks they can't easily handle on th ## Writing Effective Descriptions +Leading-word and pruning vocabulary: `skill-quality.md` only — do not restate those essays here. + ### Structure 1. First sentence: what the skill does @@ -73,7 +75,7 @@ For each query, ask: would the agent correctly decide to load/not-load this skil ### Step 4: Validate -Write 5-10 fresh queries (never used during optimization) as a holdout test. These tell you whether your changes generalize. +Write a fresh holdout set of queries never used during optimization. Prefer enough to cover each branch and near-miss (same bar as Step 1). These tell you whether your changes generalize. ### Step 5: Final check diff --git a/skills/skill-maker/references/skill-quality.md b/skills/skill-maker/references/skill-quality.md new file mode 100644 index 0000000..435af05 --- /dev/null +++ b/skills/skill-maker/references/skill-quality.md @@ -0,0 +1,50 @@ +# Skill Quality Vocabulary + +Slim local vocabulary for predictable skills. Inspired by writing-great-skills principles; self-contained — do not require installing that skill. + +**Predictability** is the root virtue: the agent takes the same *process* every run (not the same output). Every lever below serves it. + +## Information hierarchy / progressive disclosure + +Rank content by how immediately the agent needs it: + +1. **In-skill steps** — ordered actions in `SKILL.md` (primary) +2. **In-skill reference** — definitions/rules consulted on demand +3. **External reference** — material behind a **context pointer**, loaded only when the pointer fires + +**Progressive disclosure** moves reference down the ladder so the top stays legible. Inline what every branch needs; push behind a pointer what only some branches reach. + +## Context pointers + +A pointer names out-of-context material *and* the condition for loading it. Wording decides reliability — "Read `references/api-errors.md` if the API returns non-200" beats "see references/ for details." A must-have target behind a weak pointer is a variance bug: sharpen the wording before inlining. + +## Completion criteria + +Every step ends on a checkable done condition. Prefer exhaustive bars ("every modified model accounted for") over vague ones ("produce a change list"). Vague criteria invite **premature completion**. + +## Leading words + +Compact concepts already in the model's pretraining (`relentless`, `tracer bullets`, `fog of war`) that anchor behaviour in few tokens. Use them in the body for execution and in the **description** for invocation. Prefer a strong pretrained word over a long restatement. + +## Pruning + +- Keep each meaning in a **single source of truth** +- Check **relevance**: does this line still bear on what the skill does? +- Hunt **no-ops** sentence by sentence — if it doesn't change behaviour vs the default, delete it + +## Failure modes + +| Mode | Meaning | Cure | +|------|---------|------| +| **Premature completion** | Ending a step before it's done | Sharpen the completion criterion; only then hide later steps | +| **Duplication** | Same meaning in multiple places | Single-source; collapse synonyms in descriptions | +| **Sediment** | Stale layers that accumulate | Prune on every edit; removing is safer than it feels | +| **Sprawl** | Skill too long even when all lines are live | Disclose reference; split by branch/sequence | +| **No-op** | Instruction the model already obeys | Delete, or replace a weak leading word with a stronger one | +| **Negation** | Steering by prohibition ("don't X") | Prompt the positive target; keep bans only as hard guardrails paired with what to do instead | + +## When to apply + +- **Create (Phases 2–5):** Check hierarchy, pointers, completion criteria, and failure modes while drafting and reviewing +- **Audit:** Map findings to these modes when diagnosing why a skill misfires or bloats +- **Descriptions:** Front-load leading words; one trigger per branch diff --git a/skills/skill-maker/scripts/command-metadata.json b/skills/skill-maker/scripts/command-metadata.json new file mode 100644 index 0000000..1333869 --- /dev/null +++ b/skills/skill-maker/scripts/command-metadata.json @@ -0,0 +1,14 @@ +{ + "audit": { + "description": "Review, improve, or debug an existing SKILL.md. Use when auditing a skill, checking why it never triggers, or fixing skill quality.", + "argumentHint": "[skill path or name]" + }, + "create": { + "description": "Interview, draft, and review a new agent skill from scratch. Use when creating a skill or drafting a SKILL.md.", + "argumentHint": "[skill idea or domain]" + }, + "consolidate": { + "description": "Merge multiple skills into fewer. Use when consolidating, combining, or reducing skill count.", + "argumentHint": "[skill names or paths]" + } +} diff --git a/skills/skill-maker/scripts/setup.py b/skills/skill-maker/scripts/setup.py new file mode 100644 index 0000000..0da42a9 --- /dev/null +++ b/skills/skill-maker/scripts/setup.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +"""Detect whether Matt Pocock's grilling skill is installed (verify only).""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +MINIMAL_INSTALL = "npx skills@latest add mattpocock/skills --skill grilling -g -y" +RECOMMENDED_INSTALL = "npx skills@latest add mattpocock/skills --all -g" + +SKILL_RELATIVE = Path("grilling") / "SKILL.md" + + +def grilling_search_paths( + home: Path | None = None, + cwd: Path | None = None, +) -> list[Path]: + """Return candidate paths for grilling/SKILL.md (user + project-local).""" + home = home if home is not None else Path.home() + cwd = cwd if cwd is not None else Path.cwd() + return [ + home / ".claude" / "skills" / SKILL_RELATIVE, + home / ".agents" / "skills" / SKILL_RELATIVE, + home / ".cursor" / "skills" / SKILL_RELATIVE, + cwd / ".claude" / "skills" / SKILL_RELATIVE, + cwd / ".agents" / "skills" / SKILL_RELATIVE, + cwd / ".cursor" / "skills" / SKILL_RELATIVE, + ] + + +def find_grilling( + home: Path | None = None, + cwd: Path | None = None, +) -> Path | None: + """Return the first existing grilling/SKILL.md path, or None.""" + for path in grilling_search_paths(home=home, cwd=cwd): + if path.is_file(): + return path.resolve() + return None + + +def check_grilling( + home: Path | None = None, + cwd: Path | None = None, +) -> dict: + """Build a results dict for grilling skill detection.""" + found = find_grilling(home=home, cwd=cwd) + return { + "grilling_found": found is not None, + "grilling_path": str(found) if found else None, + "minimal_install": MINIMAL_INSTALL, + "recommended_install": RECOMMENDED_INSTALL, + "overall": "pass" if found else "fail", + } + + +def _output(results: dict, as_json: bool) -> None: + """Print results in JSON or human-readable format.""" + if as_json: + json.dump(results, sys.stdout, indent=2) + print() + return + + print("=" * 50) + print("skill-maker Setup Check") + print("=" * 50) + print() + print("Hard prerequisite: Matt Pocock's `grilling` skill.") + print("Create/interview paths require it for interview cadence.") + print() + + if results["grilling_found"]: + print(f" [PASS] grilling found: {results['grilling_path']}") + else: + print(" [FAIL] grilling skill not found") + print(" Looked for grilling/SKILL.md under:") + print(" ~/.claude/skills/") + print(" ~/.agents/skills/") + print(" ~/.cursor/skills/") + print(" /.claude/skills/") + print(" /.agents/skills/") + print(" /.cursor/skills/") + print() + print(" Install (after user confirms):") + print(f" Minimal (gate installs this): {MINIMAL_INSTALL}") + print(f" Recommended (full Matt pack): {RECOMMENDED_INSTALL}") + print() + print(" This script detects only — it does not install.") + + print() + print(f"Overall: {results['overall'].upper()}") + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description=( + "Detect whether Matt Pocock's grilling skill is installed. " + "Verify only — does not install." + ) + ) + parser.add_argument("--json", action="store_true", help="Output results as JSON") + args = parser.parse_args(argv) + + results = check_grilling() + _output(results, args.json) + return 0 if results["overall"] == "pass" else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/unit/test_base_images_and_rpms.py b/tests/unit/test_base_images_and_rpms.py index f046a48..1d1f443 100644 --- a/tests/unit/test_base_images_and_rpms.py +++ b/tests/unit/test_base_images_and_rpms.py @@ -22,12 +22,22 @@ def _clean_rhdh_env() -> dict[str, str]: return {k: v for k, v in os.environ.items() if k not in RHDH_ENV_VARS} +def _shell_script_cmd(script: Path, *args: str) -> list[str]: + """Build argv to run a .sh script (via bash on Windows).""" + if os.name == "nt": + bash = shutil.which("bash") + if bash is None: + pytest.skip("bash required to run .sh scripts on Windows") + return [bash, str(script), *args] + return [str(script), *args] + + def _run_analyze(*args: str, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]: run_env = _clean_rhdh_env() if env: run_env.update(env) return subprocess.run( - [str(ANALYZE_SCRIPT), *args], + _shell_script_cmd(ANALYZE_SCRIPT, *args), capture_output=True, text=True, env=run_env, @@ -68,6 +78,7 @@ def test_missing_build_scripts_dir_exits_nonzero(self, tmp_path: Path) -> None: assert result.returncode != 0 assert "Set RHDH_BUILD_SCRIPTS" in result.stderr + @pytest.mark.skipif(shutil.which("skopeo") is None, reason="skopeo not installed") def test_missing_get_latest_script_exits_nonzero(self, tmp_path: Path) -> None: scripts_dir = tmp_path / "scripts" scripts_dir.mkdir() @@ -217,7 +228,7 @@ class TestBaseImagesAndRpmsScript: def test_main_script_help_lists_analyze(self) -> None: result = subprocess.run( - [str(MAIN_SCRIPT), "--help"], + _shell_script_cmd(MAIN_SCRIPT, "--help"), capture_output=True, text=True, check=False, diff --git a/tests/unit/test_rhdh_jira_grilling_setup.py b/tests/unit/test_rhdh_jira_grilling_setup.py new file mode 100644 index 0000000..aa49490 --- /dev/null +++ b/tests/unit/test_rhdh_jira_grilling_setup.py @@ -0,0 +1,199 @@ +"""Tests for grilling skill detection in rhdh-jira setup.py.""" + +import importlib.util +import json +from pathlib import Path + +import pytest + +SETUP = Path(__file__).parents[2] / "skills/rhdh-jira/scripts/setup.py" + + +def load_setup(): + spec = importlib.util.spec_from_file_location("rhdh_jira_setup", SETUP) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +@pytest.fixture(scope="module") +def setup_mod(): + return load_setup() + + +def _write_grilling(base: Path) -> Path: + skill = base / "grilling" / "SKILL.md" + skill.parent.mkdir(parents=True) + skill.write_text("# grilling\n", encoding="utf-8") + return skill + + +def test_grilling_search_paths_order(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + paths = setup_mod.grilling_search_paths(home=home, cwd=cwd) + assert paths == [ + home / ".claude" / "skills" / "grilling" / "SKILL.md", + home / ".agents" / "skills" / "grilling" / "SKILL.md", + home / ".cursor" / "skills" / "grilling" / "SKILL.md", + cwd / ".claude" / "skills" / "grilling" / "SKILL.md", + cwd / ".agents" / "skills" / "grilling" / "SKILL.md", + cwd / ".cursor" / "skills" / "grilling" / "SKILL.md", + ] + + +def test_find_grilling_missing(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + assert setup_mod.find_grilling(home=home, cwd=cwd) is None + + +def test_find_grilling_in_claude_skills(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + expected = _write_grilling(home / ".claude" / "skills") + found = setup_mod.find_grilling(home=home, cwd=cwd) + assert found == expected.resolve() + + +def test_find_grilling_prefers_first_match(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + first = _write_grilling(home / ".claude" / "skills") + _write_grilling(home / ".agents" / "skills") + found = setup_mod.find_grilling(home=home, cwd=cwd) + assert found == first.resolve() + + +def test_find_grilling_project_local(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + expected = _write_grilling(cwd / ".agents" / "skills") + found = setup_mod.find_grilling(home=home, cwd=cwd) + assert found == expected.resolve() + + +def test_find_grilling_cursor_skills(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + expected = _write_grilling(home / ".cursor" / "skills") + found = setup_mod.find_grilling(home=home, cwd=cwd) + assert found == expected.resolve() + + +def test_find_grilling_project_local_cursor_skills(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + expected = _write_grilling(cwd / ".cursor" / "skills") + found = setup_mod.find_grilling(home=home, cwd=cwd) + assert found == expected.resolve() + + +def test_check_grilling_pass_fields(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + skill = _write_grilling(home / ".cursor" / "skills") + results = setup_mod.check_grilling(home=home, cwd=cwd) + assert results["grilling_found"] is True + assert results["grilling_path"] == str(skill.resolve()) + assert results["overall"] == "pass" + assert "grilling" in results["minimal_install"] + assert "--all -g" in results["recommended_install"] + + +def test_check_grilling_fail_fields(setup_mod, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "cwd" + home.mkdir() + cwd.mkdir() + results = setup_mod.check_grilling(home=home, cwd=cwd) + assert results["grilling_found"] is False + assert results["grilling_path"] is None + assert results["overall"] == "fail" + assert results["minimal_install"] == setup_mod.MINIMAL_GRILLING_INSTALL + assert results["recommended_install"] == setup_mod.RECOMMENDED_GRILLING_INSTALL + + +def test_grilling_only_main_exit_nonzero_when_missing(setup_mod, monkeypatch, capsys): + monkeypatch.setattr( + setup_mod, + "check_grilling", + lambda home=None, cwd=None: { + "grilling_found": False, + "grilling_path": None, + "minimal_install": setup_mod.MINIMAL_GRILLING_INSTALL, + "recommended_install": setup_mod.RECOMMENDED_GRILLING_INSTALL, + "overall": "fail", + }, + ) + + with pytest.raises(SystemExit) as exc: + setup_mod.main(["--grilling-only", "--json"]) + assert exc.value.code == 1 + payload = json.loads(capsys.readouterr().out) + assert payload["grilling_found"] is False + assert payload["overall"] == "fail" + assert payload["minimal_install"] == setup_mod.MINIMAL_GRILLING_INSTALL + assert payload["recommended_install"] == setup_mod.RECOMMENDED_GRILLING_INSTALL + + +def test_grilling_only_main_exit_zero_when_found(setup_mod, tmp_path, monkeypatch, capsys): + skill_path = str((tmp_path / "grilling" / "SKILL.md").resolve()) + monkeypatch.setattr( + setup_mod, + "check_grilling", + lambda home=None, cwd=None: { + "grilling_found": True, + "grilling_path": skill_path, + "minimal_install": setup_mod.MINIMAL_GRILLING_INSTALL, + "recommended_install": setup_mod.RECOMMENDED_GRILLING_INSTALL, + "overall": "pass", + }, + ) + + with pytest.raises(SystemExit) as exc: + setup_mod.main(["--grilling-only", "--json"]) + assert exc.value.code == 0 + payload = json.loads(capsys.readouterr().out) + assert payload["grilling_found"] is True + assert payload["grilling_path"] == skill_path + assert payload["overall"] == "pass" + + +def test_grilling_only_human_output_includes_install_hints(setup_mod, monkeypatch, capsys): + monkeypatch.setattr( + setup_mod, + "check_grilling", + lambda home=None, cwd=None: { + "grilling_found": False, + "grilling_path": None, + "minimal_install": setup_mod.MINIMAL_GRILLING_INSTALL, + "recommended_install": setup_mod.RECOMMENDED_GRILLING_INSTALL, + "overall": "fail", + }, + ) + + with pytest.raises(SystemExit) as exc: + setup_mod.main(["--grilling-only"]) + assert exc.value.code == 1 + out = capsys.readouterr().out + assert "grilling skill not found" in out + assert setup_mod.MINIMAL_GRILLING_INSTALL in out + assert setup_mod.RECOMMENDED_GRILLING_INSTALL in out + assert "does not install" in out diff --git a/tests/unit/test_skill_maker_grilling_setup.py b/tests/unit/test_skill_maker_grilling_setup.py new file mode 100644 index 0000000..cdb8282 --- /dev/null +++ b/tests/unit/test_skill_maker_grilling_setup.py @@ -0,0 +1,153 @@ +"""Unit tests for skill-maker grilling prerequisite setup checker.""" + +from __future__ import annotations + +import importlib.util +import json +import sys +from pathlib import Path + +SETUP_PATH = Path(__file__).resolve().parents[2] / "skills" / "skill-maker" / "scripts" / "setup.py" + + +def _load_setup(): + """Load skill-maker setup.py as a module without package install.""" + spec = importlib.util.spec_from_file_location("skill_maker_setup", SETUP_PATH) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +setup = _load_setup() + + +def _place_grilling(root: Path) -> Path: + """Create a fake grilling/SKILL.md under root/skills and return its path.""" + skill_md = root / "skills" / "grilling" / "SKILL.md" + skill_md.parent.mkdir(parents=True, exist_ok=True) + skill_md.write_text("---\nname: grilling\n---\n", encoding="utf-8") + return skill_md.resolve() + + +class TestGrillingSearchPaths: + def test_includes_user_and_project_locations(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + paths = setup.grilling_search_paths(home=home, cwd=cwd) + assert home / ".claude" / "skills" / "grilling" / "SKILL.md" in paths + assert home / ".agents" / "skills" / "grilling" / "SKILL.md" in paths + assert home / ".cursor" / "skills" / "grilling" / "SKILL.md" in paths + assert cwd / ".claude" / "skills" / "grilling" / "SKILL.md" in paths + assert cwd / ".agents" / "skills" / "grilling" / "SKILL.md" in paths + assert cwd / ".cursor" / "skills" / "grilling" / "SKILL.md" in paths + + +class TestFindGrilling: + def test_missing_returns_none(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + cwd.mkdir() + assert setup.find_grilling(home=home, cwd=cwd) is None + + def test_found_in_claude_skills(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + cwd.mkdir() + expected = _place_grilling(home / ".claude") + assert setup.find_grilling(home=home, cwd=cwd) == expected + + def test_found_in_project_local_agents(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + expected = _place_grilling(cwd / ".agents") + assert setup.find_grilling(home=home, cwd=cwd) == expected + + def test_found_in_project_local_cursor(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + expected = _place_grilling(cwd / ".cursor") + assert setup.find_grilling(home=home, cwd=cwd) == expected + + def test_prefers_first_match_in_search_order(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + first = _place_grilling(home / ".claude") + _place_grilling(home / ".cursor") + assert setup.find_grilling(home=home, cwd=cwd) == first + + +class TestCheckGrilling: + def test_pass_when_found(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + cwd.mkdir() + path = _place_grilling(home / ".cursor") + result = setup.check_grilling(home=home, cwd=cwd) + assert result["grilling_found"] is True + assert result["grilling_path"] == str(path) + assert result["overall"] == "pass" + assert ( + "npx skills@latest add mattpocock/skills --skill grilling" in result["minimal_install"] + ) + assert "--all -g" in result["recommended_install"] + + def test_fail_when_missing(self, tmp_path): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + cwd.mkdir() + result = setup.check_grilling(home=home, cwd=cwd) + assert result["grilling_found"] is False + assert result["grilling_path"] is None + assert result["overall"] == "fail" + + +class TestMainCli: + def test_exit_zero_when_found(self, tmp_path, monkeypatch, capsys): + home = tmp_path / "home" + cwd = tmp_path / "project" + cwd.mkdir() + _place_grilling(home / ".claude") + fixed = setup.check_grilling(home=home, cwd=cwd) + monkeypatch.setattr(setup, "check_grilling", lambda *a, **k: fixed) + + code = setup.main(["--json"]) + assert code == 0 + payload = json.loads(capsys.readouterr().out) + assert payload["overall"] == "pass" + assert payload["grilling_found"] is True + + def test_exit_nonzero_when_missing(self, tmp_path, monkeypatch, capsys): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + cwd.mkdir() + fixed = setup.check_grilling(home=home, cwd=cwd) + monkeypatch.setattr(setup, "check_grilling", lambda *a, **k: fixed) + + code = setup.main(["--json"]) + assert code == 1 + payload = json.loads(capsys.readouterr().out) + assert payload["overall"] == "fail" + assert payload["grilling_found"] is False + + def test_human_output_mentions_prereq_and_install_hints(self, tmp_path, monkeypatch, capsys): + home = tmp_path / "home" + cwd = tmp_path / "project" + home.mkdir() + cwd.mkdir() + fixed = setup.check_grilling(home=home, cwd=cwd) + monkeypatch.setattr(setup, "check_grilling", lambda *a, **k: fixed) + + code = setup.main([]) + assert code == 1 + out = capsys.readouterr().out + assert "Hard prerequisite" in out + assert setup.MINIMAL_INSTALL in out + assert setup.RECOMMENDED_INSTALL in out + assert "detects only" in out