@skilly-hand/skilly-hand 0.23.3 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -16,6 +16,40 @@ All notable changes to this project are documented in this file.
16
16
  ### Removed
17
17
  - _None._
18
18
 
19
+ ## [0.25.0] - 2026-04-27
20
+ [View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.25.0)
21
+
22
+ ### Added
23
+ - Added the `roaster` planning challenge skill to critique plans, assumptions, sequencing, risks, and verification before implementation.
24
+ - Added native skill hook/rule metadata support so installed skills can surface required guidance in generated native adapter files.
25
+
26
+ ### Changed
27
+ - Updated native setup output and CLI guidance to describe rule/hook adapters alongside native instruction files.
28
+ - Exported deterministic native hook collection from core and included `nativeHooks` plus `nativeHooksStatus` in native setup plan output.
29
+
30
+ ### Fixed
31
+ - _None._
32
+
33
+ ### Removed
34
+ - _None._
35
+
36
+ ## [0.24.0] - 2026-04-26
37
+ [View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.24.0)
38
+
39
+ ### Added
40
+ - Added install-time creation of the user-owned `.ai/DECISIONS.md` decisions registry, including entry criteria, an entry template, and a required registry changelog section.
41
+ - Added CLI install output that reports the `.ai/DECISIONS.md` decisions registry status during dry runs and applied installs.
42
+ - Added regression coverage for decisions registry planning, creation, existing-registry preservation, uninstall preservation, and invalid `.ai` parent handling.
43
+
44
+ ### Changed
45
+ - Updated `review-rangers` to own decisions registry read/write guidance and bumped the skill metadata version to `1.1.0`.
46
+
47
+ ### Fixed
48
+ - Preserved existing user-owned decisions registry content across reinstalls and uninstalls.
49
+
50
+ ### Removed
51
+ - _None._
52
+
19
53
  ## [0.23.3] - 2026-04-20
20
54
  [View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.23.3)
21
55
 
package/catalog/README.md CHANGED
@@ -14,6 +14,7 @@ Published portable skills consumed by the `skilly-hand` CLI.
14
14
  | `project-teacher` | Scan the active project and teach any concept, code path, or decision using verified information, interactive questions, and simple explanations. Trigger: user asks to explain, understand, clarify, or learn about anything in the project or codebase. | core, workflow, education | all |
15
15
  | `react-guidelines` | Guide React code generation and review using latest stable React verification and modern framework best practices. | react, frontend, workflow, best-practices | all |
16
16
  | `review-rangers` | Review code, decisions, and artifacts through a multi-perspective committee and a domain expert safety guard, then synthesize a structured verdict. | core, workflow, review, quality | all |
17
+ | `roaster` | Challenge plans with constructive roast-style critique that exposes weak assumptions, missing angles, shallow sequencing, and unclear success criteria. Trigger: when the user proposes, requests, or evaluates a plan of any kind. | core, workflow, planning, quality | all |
17
18
  | `skill-creator` | Create and standardize AI skills with reusable structure, metadata rules, and templates. | core, workflow, authoring | all |
18
19
  | `spec-driven-development` | Plan, execute, and verify multi-step work through versioned specs with small, testable tasks. | core, workflow, planning | all |
19
20
  | `test-driven-development` | Guide implementation using the RED → GREEN → REFACTOR TDD cycle: write a failing test first, write the minimum code to pass, then refactor while tests stay green. | testing, workflow, quality, core | all |
@@ -9,6 +9,7 @@
9
9
  "project-teacher",
10
10
  "react-guidelines",
11
11
  "review-rangers",
12
+ "roaster",
12
13
  "skill-creator",
13
14
  "spec-driven-development",
14
15
  "test-driven-development",
@@ -3,13 +3,15 @@ name: "review-rangers"
3
3
  description: "Review code, decisions, and artifacts through a multi-perspective committee and a domain expert safety guard, then synthesize a structured verdict."
4
4
  skillMetadata:
5
5
  author: "skilly-hand"
6
- last-edit: "2026-04-04"
6
+ last-edit: "2026-04-26"
7
7
  license: "Apache-2.0"
8
- version: "1.0.0"
9
- changelog: "Added multi-perspective review skill with committee + safety guard synthesis; enables adversarial evaluation without permanent agent files; affects catalog skill coverage for review and quality workflows"
8
+ version: "1.1.0"
9
+ changelog: "Added DECISIONS.md registry ownership guidance; preserves durable review insights and anti-slop decisions across sessions; affects review-rangers workflow, install scaffolding, and project memory usage"
10
10
  auto-invoke: "Reviewing code, decisions, or artifacts where adversarial multi-perspective evaluation adds value"
11
11
  allowed-tools:
12
12
  - "Read"
13
+ - "Edit"
14
+ - "Write"
13
15
  - "Grep"
14
16
  - "Glob"
15
17
  - "Bash"
@@ -38,14 +40,16 @@ Do not use this skill for:
38
40
  ## Core Workflow
39
41
 
40
42
  1. Identify the target (code, decision, artifact) and its domain.
41
- 2. Determine committee size: 3 members for routine reviews, 5 for high-risk or cross-domain targets.
42
- 3. Spawn N committee members using `assets/committee-member-template.md`. Assign each a distinct evaluation lens. Run them independently — no member sees another's output.
43
- 4. Determine the expert domain for the safety guard.
44
- 5. Spawn 1 safety guard using `assets/safety-guard-template.md`. It evaluates the target from an authoritative expert position.
45
- 6. Run the committee and safety guard in parallel.
46
- 7. Collect all outputs.
47
- 8. Synthesize a structured verdict following the Synthesis Rules.
48
- 9. Emit the final verdict with confidence tier, top findings, and recommended action.
43
+ 2. Read `.ai/DECISIONS.md` if it exists. Treat it as project memory for avoiding repeated mistakes and reusing documented decisions.
44
+ 3. Determine committee size: 3 members for routine reviews, 5 for high-risk or cross-domain targets.
45
+ 4. Spawn N committee members using `assets/committee-member-template.md`. Assign each a distinct evaluation lens. Run them independently — no member sees another's output.
46
+ 5. Determine the expert domain for the safety guard.
47
+ 6. Spawn 1 safety guard using `assets/safety-guard-template.md`. It evaluates the target from an authoritative expert position.
48
+ 7. Run the committee and safety guard in parallel.
49
+ 8. Collect all outputs.
50
+ 9. Synthesize a structured verdict following the Synthesis Rules.
51
+ 10. Emit the final verdict with confidence tier, top findings, and recommended action.
52
+ 11. Decide whether any insight qualifies for `.ai/DECISIONS.md`; if yes, update the registry and its changelog in the same edit.
49
53
 
50
54
  ---
51
55
 
@@ -142,6 +146,56 @@ RECOMMENDED ACTION:
142
146
 
143
147
  ---
144
148
 
149
+ ## Decisions Registry Protocol
150
+
151
+ `review-rangers` owns `.ai/DECISIONS.md` maintenance when the registry exists. Use it as both:
152
+
153
+ - A documentary source before solving or reviewing relevant problems.
154
+ - A durable memory target after review when a finding has future value.
155
+
156
+ ### Read Rules
157
+
158
+ - Read `.ai/DECISIONS.md` near the start of relevant review or problem-solving work.
159
+ - Apply documented decisions and "avoid repeating" notes as project constraints.
160
+ - If the file does not exist, continue the review without creating it unless the current task is installation or explicit registry setup.
161
+
162
+ ### Write Criteria
163
+
164
+ Write to `.ai/DECISIONS.md` only for:
165
+
166
+ - Breaking changes.
167
+ - Mid-interest or high-interest solutions.
168
+ - Architectural decisions.
169
+ - Repeated issue patterns.
170
+ - Project-specific conventions likely to matter in future sessions.
171
+
172
+ Do not write entries for minimal cleanup, obvious one-off bugs, insignificant changes, local-only implementation details, or full review transcripts.
173
+
174
+ ### Write Format
175
+
176
+ Insert new entries above the final `## Changelog` section so the changelog remains the last section.
177
+
178
+ ```md
179
+ ## YYYY-MM-DD - Short Decision Title
180
+
181
+ - Interest level: Mid | High | Breaking
182
+ - Context:
183
+ - Decision / Insight:
184
+ - Rationale:
185
+ - Avoid repeating:
186
+ - Source:
187
+ ```
188
+
189
+ Every change to `.ai/DECISIONS.md` must update `## Changelog` in the same edit.
190
+
191
+ ```md
192
+ - YYYY-MM-DD: Created/updated entry "<title>" because <why>.
193
+ ```
194
+
195
+ If the changelog section is missing, add it as the final section before making any other registry change.
196
+
197
+ ---
198
+
145
199
  ## Decision Tree
146
200
 
147
201
  ```text
@@ -10,13 +10,15 @@
10
10
  "agentSupport": ["codex", "claude", "cursor", "gemini", "copilot", "antigravity", "windsurf", "trae"],
11
11
  "skillMetadata": {
12
12
  "author": "skilly-hand",
13
- "last-edit": "2026-04-04",
13
+ "last-edit": "2026-04-26",
14
14
  "license": "Apache-2.0",
15
- "version": "1.0.0",
16
- "changelog": "Added multi-perspective review skill with committee + safety guard synthesis; enables adversarial evaluation without permanent agent files; affects catalog skill coverage for review and quality workflows",
15
+ "version": "1.1.0",
16
+ "changelog": "Added DECISIONS.md registry ownership guidance; preserves durable review insights and anti-slop decisions across sessions; affects review-rangers workflow, install scaffolding, and project memory usage",
17
17
  "auto-invoke": "Reviewing code, decisions, or artifacts where adversarial multi-perspective evaluation adds value",
18
18
  "allowed-tools": [
19
19
  "Read",
20
+ "Edit",
21
+ "Write",
20
22
  "Grep",
21
23
  "Glob",
22
24
  "Bash",
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: "roaster"
3
+ description: "Challenge plans with constructive roast-style critique that exposes weak assumptions, missing angles, shallow sequencing, and unclear success criteria. Trigger: when the user proposes, requests, or evaluates a plan of any kind."
4
+ skillMetadata:
5
+ author: "skilly-hand"
6
+ last-edit: "2026-04-27"
7
+ license: "Apache-2.0"
8
+ version: "1.0.0"
9
+ changelog: "Added roaster planning challenge skill; improves plan quality by forcing constructive skepticism before agreement; affects planning critique workflows and auto-invoke routing"
10
+ auto-invoke: "When the user proposes, requests, or evaluates a plan of any kind"
11
+ allowed-tools:
12
+ - "Read"
13
+ - "Edit"
14
+ - "Write"
15
+ - "Glob"
16
+ - "Grep"
17
+ - "Bash"
18
+ - "Task"
19
+ ---
20
+ # Roaster Guide
21
+
22
+ ## When to Use
23
+
24
+ Use this skill when:
25
+
26
+ - The user proposes, requests, or evaluates a plan.
27
+ - A plan sounds under-specified, too agreeable, or too easy.
28
+ - The user needs stronger assumptions, sharper scope, or better sequencing.
29
+ - The work would benefit from a skeptical partner before execution.
30
+
31
+ Do not use this skill for:
32
+
33
+ - Emergencies where speed matters more than critique.
34
+ - Trivial one-step tasks with no meaningful planning surface.
35
+ - Sensitive emotional, medical, legal, or crisis conversations where roast tone would be inappropriate.
36
+ - Personal attacks, identity jokes, humiliation, slurs, or cruelty.
37
+
38
+ ---
39
+
40
+ ## Critical Patterns
41
+
42
+ ### Pattern 1: Challenge First, Agree Second
43
+
44
+ Default posture:
45
+
46
+ ```text
47
+ Do not start with "yes, you are right."
48
+ First identify the weakest part of the plan.
49
+ Then acknowledge what works, if anything works.
50
+ End with a stronger version of the plan or the questions needed to make one.
51
+ ```
52
+
53
+ The target is the plan, not the person. Roast the gap between ambition and current rigor.
54
+
55
+ ### Pattern 2: Constructive Roast Boundaries
56
+
57
+ Allowed:
58
+
59
+ - Witty, direct critique of vague goals, missing constraints, shallow sequencing, or lazy acceptance criteria.
60
+ - High standards, pointed questions, and clear pushback.
61
+ - Humor that helps the user think harder.
62
+
63
+ Not allowed:
64
+
65
+ - Insults about intelligence, identity, background, appearance, worth, or mental health.
66
+ - Discriminatory, sexual, threatening, or demeaning language.
67
+ - Sarcasm that leaves the user with no actionable next step.
68
+
69
+ ### Pattern 3: Full-Angle Critique
70
+
71
+ Check every real plan against these angles:
72
+
73
+ | Angle | Challenge |
74
+ | --- | --- |
75
+ | Goal | Is the outcome specific enough to judge success? |
76
+ | Assumptions | What is being treated as true without evidence? |
77
+ | Stakeholders | Who is affected, blocked, or missing from the plan? |
78
+ | Scope | What is included, excluded, and dangerously implied? |
79
+ | Risks | What can fail technically, socially, financially, or operationally? |
80
+ | Sequencing | Are steps ordered by dependency, learning value, and risk reduction? |
81
+ | Alternatives | Is there a simpler, more complete, or more durable path? |
82
+ | Verification | How will the user prove the result is good enough? |
83
+
84
+ ### Pattern 4: Escalate With Stakes
85
+
86
+ Use light critique for small plans. Escalate to deeper challenge when the plan affects:
87
+
88
+ - Architecture or long-term maintainability.
89
+ - Security, privacy, or safety.
90
+ - Delivery timelines, money, reputation, or users.
91
+ - Irreversible decisions or broad organizational impact.
92
+
93
+ ---
94
+
95
+ ## Response Format
96
+
97
+ Use this structure by default:
98
+
99
+ ```text
100
+ Verdict: {short judgment}
101
+
102
+ Roast: {constructive jab at the weakest part}
103
+
104
+ Blind Spots:
105
+ - {missing angle}
106
+ - {missing angle}
107
+
108
+ Upgrade:
109
+ - {specific improvement}
110
+ - {specific improvement}
111
+
112
+ Questions:
113
+ - {question that materially improves the plan}
114
+ ```
115
+
116
+ Keep it compact unless the plan is high-risk or the user asks for a deeper review.
117
+
118
+ ---
119
+
120
+ ## Decision Tree
121
+
122
+ ```text
123
+ Is this a plan or planning request? -> Use roaster
124
+ Is it trivial and one-step? -> Skip or give one-line challenge
125
+ Does it affect high-stakes outcomes? -> Deep critique across all angles
126
+ Is the user asking for validation only? -> Challenge before validating
127
+ Is roast tone unsafe for the situation? -> Switch to firm, compassionate critique
128
+ Otherwise -> Constructive roast with actionable upgrade
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Examples
134
+
135
+ ### Example 1: Vague Product Plan
136
+
137
+ ```text
138
+ Verdict: Promising, but currently held together with vibes and hope.
139
+
140
+ Roast: "Launch the feature" is not a plan; it is a calendar event wearing a fake mustache.
141
+
142
+ Blind Spots:
143
+ - No target user or success metric.
144
+ - No rollback or support path.
145
+
146
+ Upgrade:
147
+ - Define the primary user, the measurable outcome, and the smallest launch slice.
148
+ - Add one validation step before build and one verification step after release.
149
+
150
+ Questions:
151
+ - What evidence would prove this is worth building before you spend the full effort?
152
+ ```
153
+
154
+ ### Example 2: Technical Refactor Plan
155
+
156
+ ```text
157
+ Verdict: The direction is reasonable, but the blast radius is undercooked.
158
+
159
+ Roast: "Refactor the service" is how regressions enter the room wearing a nice jacket.
160
+
161
+ Blind Spots:
162
+ - No compatibility strategy for existing callers.
163
+ - No test boundary around current behavior.
164
+
165
+ Upgrade:
166
+ - Capture current behavior with focused tests before changing internals.
167
+ - Refactor behind the existing public interface first, then evaluate API changes separately.
168
+
169
+ Questions:
170
+ - Which behavior must remain identical after the refactor?
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Commands
176
+
177
+ ```bash
178
+ rg -n "plan|proposal|roadmap|strategy|approach" .
179
+ rg -n "success criteria|acceptance criteria|risks|assumptions" .
180
+ ```
@@ -0,0 +1,41 @@
1
+ {
2
+ "id": "roaster",
3
+ "title": "Roaster",
4
+ "description": "Challenge plans with constructive roast-style critique that exposes weak assumptions, missing angles, shallow sequencing, and unclear success criteria. Trigger: when the user proposes, requests, or evaluates a plan of any kind.",
5
+ "portable": true,
6
+ "tags": ["core", "workflow", "planning", "quality"],
7
+ "detectors": ["always"],
8
+ "detectionTriggers": ["always"],
9
+ "installsFor": ["all"],
10
+ "agentSupport": ["codex", "claude", "cursor", "gemini", "copilot", "antigravity", "windsurf", "trae"],
11
+ "nativeHooks": [
12
+ {
13
+ "id": "plan-challenge",
14
+ "trigger": "When the user proposes, requests, or evaluates a plan of any kind",
15
+ "instruction": "Invoke roaster to critique assumptions, scope, sequencing, risks, and verification before agreeing with the plan.",
16
+ "priority": 30,
17
+ "enforcement": "required"
18
+ }
19
+ ],
20
+ "skillMetadata": {
21
+ "author": "skilly-hand",
22
+ "last-edit": "2026-04-27",
23
+ "license": "Apache-2.0",
24
+ "version": "1.0.0",
25
+ "changelog": "Added roaster planning challenge skill; improves plan quality by forcing constructive skepticism before agreement; affects planning critique workflows and auto-invoke routing",
26
+ "auto-invoke": "When the user proposes, requests, or evaluates a plan of any kind",
27
+ "allowed-tools": [
28
+ "Read",
29
+ "Edit",
30
+ "Write",
31
+ "Glob",
32
+ "Grep",
33
+ "Bash",
34
+ "Task"
35
+ ]
36
+ },
37
+ "files": [
38
+ { "path": "SKILL.md", "kind": "instruction" }
39
+ ],
40
+ "dependencies": []
41
+ }
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@skilly-hand/skilly-hand",
3
- "version": "0.23.3",
3
+ "version": "0.25.0",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Davecelot/skilly-hand.git"
9
+ },
6
10
  "publishConfig": {
7
11
  "access": "public"
8
12
  },
@@ -18,7 +22,8 @@
18
22
  "SECURITY.md"
19
23
  ],
20
24
  "workspaces": [
21
- "packages/*"
25
+ "packages/*",
26
+ "site"
22
27
  ],
23
28
  "engines": {
24
29
  "node": ">=22.0.0"
@@ -47,7 +52,10 @@
47
52
  "cli": "node ./packages/cli/src/bin.js",
48
53
  "detect": "node ./packages/cli/src/bin.js detect",
49
54
  "list": "node ./packages/cli/src/bin.js list",
50
- "doctor": "node ./packages/cli/src/bin.js doctor"
55
+ "doctor": "node ./packages/cli/src/bin.js doctor",
56
+ "site:dev": "npm run dev -w @skilly-hand/site",
57
+ "site:build": "npm run build -w @skilly-hand/site",
58
+ "site:preview": "npm run preview -w @skilly-hand/site"
51
59
  },
52
60
  "dependencies": {
53
61
  "inquirer": "13.4.1"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skilly-hand/catalog",
3
- "version": "0.23.3",
3
+ "version": "0.25.0",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -80,6 +80,8 @@ export function validateSkillManifest(manifest) {
80
80
  throw new Error(`Skill "${manifest.id}" must declare files`);
81
81
  }
82
82
 
83
+ validateNativeHooks(manifest);
84
+
83
85
  const hasSkillInstruction = manifest.files.some((file) => file.path === "SKILL.md" && file.kind === "instruction");
84
86
  if (!hasSkillInstruction) {
85
87
  throw new Error(`Skill "${manifest.id}" must include files entry for SKILL.md as instruction`);
@@ -90,6 +92,36 @@ export function validateSkillManifest(manifest) {
90
92
  return true;
91
93
  }
92
94
 
95
+ function validateNativeHooks(manifest) {
96
+ if (!("nativeHooks" in manifest)) {
97
+ return;
98
+ }
99
+
100
+ if (!Array.isArray(manifest.nativeHooks)) {
101
+ throw new Error(`Skill "${manifest.id}" must declare nativeHooks as an array when present`);
102
+ }
103
+
104
+ for (const hook of manifest.nativeHooks) {
105
+ if (!hook || typeof hook !== "object" || Array.isArray(hook)) {
106
+ throw new Error(`Skill "${manifest.id}" has invalid nativeHooks entry; expected an object`);
107
+ }
108
+
109
+ for (const key of ["id", "trigger", "instruction", "enforcement"]) {
110
+ if (typeof hook[key] !== "string" || hook[key].trim().length === 0) {
111
+ throw new Error(`Skill "${manifest.id}" has invalid nativeHooks.${key}; expected a non-empty string`);
112
+ }
113
+ }
114
+
115
+ if (!["required", "recommended"].includes(hook.enforcement)) {
116
+ throw new Error(`Skill "${manifest.id}" has invalid nativeHooks.enforcement; expected required or recommended`);
117
+ }
118
+
119
+ if (!Number.isFinite(hook.priority)) {
120
+ throw new Error(`Skill "${manifest.id}" has invalid nativeHooks.priority; expected a finite number`);
121
+ }
122
+ }
123
+ }
124
+
93
125
  function toLf(text) {
94
126
  return text.replaceAll("\r\n", "\n");
95
127
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skilly-hand/cli",
3
- "version": "0.23.3",
3
+ "version": "0.25.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "bin": {
@@ -131,11 +131,24 @@ function buildHelpText(renderer, appVersion) {
131
131
 
132
132
  function buildInstallResultDoc(result, flags, detectionGridText = "") {
133
133
  const mode = flags.dryRun ? "dry-run" : "apply";
134
+ const decisionsRegistry = result.plan.decisionsRegistry || {
135
+ relativePath: ".ai/DECISIONS.md",
136
+ exists: false,
137
+ willCreate: false
138
+ };
139
+ const decisionsRegistryStatus = decisionsRegistry.created
140
+ ? "created"
141
+ : decisionsRegistry.exists
142
+ ? "existing"
143
+ : decisionsRegistry.willCreate
144
+ ? "will create"
145
+ : "not reported";
134
146
  return createResultDoc("Install", [
135
147
  section("Install Preflight", [
136
148
  kvBlock([
137
149
  ["Project", result.plan.cwd],
138
150
  ["Install root", result.plan.installRoot],
151
+ ["Decisions registry", `${decisionsRegistry.relativePath} (${decisionsRegistryStatus})`],
139
152
  ["Agents", result.plan.agents.join(", ") || "none"],
140
153
  ["Include tags", flags.include.join(", ") || "none"],
141
154
  ["Exclude tags", flags.exclude.join(", ") || "none"],
@@ -173,7 +186,7 @@ function buildInstallResultDoc(result, flags, detectionGridText = "") {
173
186
  result.applied
174
187
  ? [
175
188
  "Review generated AGENTS and assistant instruction files.",
176
- "Run `npx skilly-hand native setup` to scaffold native instruction/rule adapters.",
189
+ "Run `npx skilly-hand native setup` to scaffold native instruction/rule/hook adapters.",
177
190
  "Run `npx skilly-hand doctor` to validate installation health.",
178
191
  "Use `npx skilly-hand uninstall` to restore backed-up files if needed."
179
192
  ]
@@ -215,7 +228,7 @@ function buildNativeSetupResultDoc(result, flags) {
215
228
  ]),
216
229
  section("Status", [
217
230
  result.applied
218
- ? statusBlock("success", "Native setup completed.", "Native rule/instruction files are synchronized.")
231
+ ? statusBlock("success", "Native setup completed.", "Native rule/hook/instruction files are synchronized.")
219
232
  : statusBlock("info", "Native setup dry run complete.", "No files were written.")
220
233
  ]),
221
234
  section("Next Steps", [
@@ -223,10 +236,10 @@ function buildNativeSetupResultDoc(result, flags) {
223
236
  result.applied
224
237
  ? [
225
238
  "Run `npx skilly-hand doctor` to verify native coverage.",
226
- "Re-run `npx skilly-hand native setup` after changing agent targets."
239
+ "Re-run `npx skilly-hand native setup` after changing agent targets or skill hook metadata."
227
240
  ]
228
241
  : [
229
- "Run `npx skilly-hand native setup` to apply these native adapter changes."
242
+ "Run `npx skilly-hand native setup` to apply these native rule/hook adapter changes."
230
243
  ]
231
244
  )
232
245
  ])
@@ -10,7 +10,7 @@ const CLI_COMMANDS = [
10
10
  {
11
11
  value: "native-setup",
12
12
  label: "Native Setup",
13
- description: "Sync native assistant adapters and instruction files.",
13
+ description: "Sync native assistant adapters, rules, hooks, and instruction files.",
14
14
  bestFor: "After install or when assistant targets change",
15
15
  aliases: ["native", "adapters"],
16
16
  usage: "npx skilly-hand native setup"
@@ -105,4 +105,3 @@ export function formatHelpUsageLines() {
105
105
  ...CLI_COMMANDS.map((command) => command.usage)
106
106
  ];
107
107
  }
108
-
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skilly-hand/core",
3
- "version": "0.23.3",
3
+ "version": "0.25.0",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -6,6 +6,35 @@ import { detectProject, inspectProjectFiles } from "../../detectors/src/index.js
6
6
  export const DEFAULT_AGENTS = ["standard", "codex", "claude", "cursor", "gemini", "copilot", "antigravity", "windsurf", "trae"];
7
7
  const MANAGED_MARKER = "<!-- Managed by skilly-hand.";
8
8
  const NATIVE_SETUP_MARKER = "<!-- Managed by skilly-hand native setup.";
9
+ const DECISIONS_REGISTRY_RELATIVE_PATH = ".ai/DECISIONS.md";
10
+ const DECISIONS_REGISTRY_TEMPLATE = `# AI Decisions
11
+
12
+ Durable project memory for \`review-rangers\`. Use this file to record breaking changes, mid/high-interest solutions, and important review insights that future agents should reuse.
13
+
14
+ ## Entry Criteria
15
+
16
+ - Add entries only for breaking changes, mid/high-interest solutions, architectural decisions, repeated issue patterns, or project-specific conventions with future value.
17
+ - Do not add minimal, obvious, one-off, or insignificant changes.
18
+ - Do not paste full review transcripts.
19
+ - Every change to this file must update the changelog at the end.
20
+
21
+ ## Entry Template
22
+
23
+ \`\`\`md
24
+ ## YYYY-MM-DD - Short Decision Title
25
+
26
+ - Interest level: Mid | High | Breaking
27
+ - Context:
28
+ - Decision / Insight:
29
+ - Rationale:
30
+ - Avoid repeating:
31
+ - Source:
32
+ \`\`\`
33
+
34
+ ## Changelog
35
+
36
+ - YYYY-MM-DD: Created/updated entry "<title>" because <why>.
37
+ `;
9
38
  const AGENT_INSTALL_PROFILES = {
10
39
  standard: {
11
40
  instructionFiles: [["AGENTS.md"]],
@@ -149,19 +178,57 @@ function resolveNativeAdapterTarget(cwd, adapter) {
149
178
  return path.join(cwd, ...adapter.targetPath);
150
179
  }
151
180
 
152
- function buildNativeRuleContent(agent, adapter) {
181
+ export function collectNativeHooks({ catalog, skillIds = [] }) {
182
+ const selected = new Set(skillIds);
183
+ return catalog
184
+ .filter((skill) => selected.has(skill.id))
185
+ .flatMap((skill) => (skill.nativeHooks || []).map((hook) => ({
186
+ skillId: skill.id,
187
+ skillTitle: skill.title,
188
+ id: hook.id,
189
+ trigger: hook.trigger,
190
+ instruction: hook.instruction,
191
+ priority: hook.priority,
192
+ enforcement: hook.enforcement
193
+ })))
194
+ .sort((a, b) => (
195
+ a.priority - b.priority ||
196
+ a.skillId.localeCompare(b.skillId) ||
197
+ a.id.localeCompare(b.id)
198
+ ));
199
+ }
200
+
201
+ function renderNativeHookLines(nativeHooks, nativeHooksStatus) {
202
+ if (nativeHooks.length === 0) {
203
+ const emptyMessage = nativeHooksStatus === "not-installed"
204
+ ? "No installed skill hooks found. Run `npx skilly-hand install` before native setup to enable skill-driven rules."
205
+ : "No installed skills declare native hooks or rules.";
206
+ return [`- ${emptyMessage}`];
207
+ }
208
+
209
+ return nativeHooks.flatMap((hook) => [
210
+ `- [${hook.enforcement}] ${hook.skillId}/${hook.id}`,
211
+ ` - Trigger: ${hook.trigger}`,
212
+ ` - Rule: ${hook.instruction}`
213
+ ]);
214
+ }
215
+
216
+ function buildNativeRuleContent(agent, adapter, nativeHooks = [], nativeHooksStatus = "not-installed") {
153
217
  const trigger = "Run token-optimizer before review-rangers when doing risk-heavy review passes.";
154
218
  return [
155
219
  `${NATIVE_SETUP_MARKER} Re-run \`npx skilly-hand native setup\` to regenerate. -->`,
156
220
  `# skilly-hand Native Bootstrap (${agent})`,
157
221
  "",
158
- `This file is managed by skilly-hand to keep native ${adapter.mode.replace("_", " ")} behavior consistent.`,
222
+ `This file is managed by skilly-hand to keep native ${adapter.mode.replace("_", " ")} rules/hooks consistent.`,
159
223
  "",
160
224
  "## Always-On Defaults",
161
225
  "- Apply AGENTS guidance from the repository root before task routing.",
162
226
  "- Enforce optimizer gate order: `token-optimizer` then `output-optimizer`.",
163
227
  "- Keep output concise by default (`step-brief`) unless user asks otherwise.",
164
228
  "",
229
+ "## Skill Hooks / Rules",
230
+ ...renderNativeHookLines(nativeHooks, nativeHooksStatus),
231
+ "",
165
232
  "## Token-Safe Review Stage",
166
233
  `- ${trigger}`,
167
234
  "- Keep review verdicts concise unless a blocker requires expanded rationale.",
@@ -263,10 +330,60 @@ export function buildInstallPlan({ cwd, detections, skills, agents }) {
263
330
  tags: skill.tags
264
331
  })),
265
332
  installRoot: path.join(cwd, ".skilly-hand"),
333
+ decisionsRegistry: {
334
+ path: path.join(cwd, ".ai", "DECISIONS.md"),
335
+ relativePath: DECISIONS_REGISTRY_RELATIVE_PATH,
336
+ exists: false,
337
+ willCreate: true
338
+ },
266
339
  generatedAt: nowIso()
267
340
  };
268
341
  }
269
342
 
343
+ async function planDecisionsRegistry(cwd) {
344
+ const aiDir = path.join(cwd, ".ai");
345
+ const registryPath = path.join(cwd, ".ai", "DECISIONS.md");
346
+
347
+ if (await exists(aiDir)) {
348
+ const info = await lstat(aiDir);
349
+ if (!info.isDirectory()) {
350
+ throw new Error("Cannot create decisions registry because .ai exists and is not a directory.");
351
+ }
352
+ }
353
+
354
+ let registryExists = false;
355
+ if (await exists(registryPath)) {
356
+ const info = await lstat(registryPath);
357
+ if (!info.isFile()) {
358
+ throw new Error("Cannot use decisions registry because .ai/DECISIONS.md exists and is not a file.");
359
+ }
360
+ registryExists = true;
361
+ }
362
+
363
+ return {
364
+ path: registryPath,
365
+ relativePath: DECISIONS_REGISTRY_RELATIVE_PATH,
366
+ exists: registryExists,
367
+ willCreate: !registryExists
368
+ };
369
+ }
370
+
371
+ async function ensureDecisionsRegistry(cwd) {
372
+ const registry = await planDecisionsRegistry(cwd);
373
+ if (registry.exists) {
374
+ return registry;
375
+ }
376
+
377
+ await mkdir(path.dirname(registry.path), { recursive: true });
378
+ await writeFile(registry.path, DECISIONS_REGISTRY_TEMPLATE, "utf8");
379
+ return {
380
+ ...registry,
381
+ exists: true,
382
+ willCreate: false,
383
+ created: true
384
+ };
385
+ }
386
+
270
387
  async function backupPathIfNeeded(targetPath, backupsDir, lockData) {
271
388
  if (!(await exists(targetPath))) {
272
389
  return null;
@@ -493,6 +610,10 @@ export async function setupNativeProject({
493
610
  const lockPath = path.join(installRoot, "manifest.lock.json");
494
611
  const previousLock = await exists(lockPath) ? await readJson(lockPath) : null;
495
612
  const selectedAgents = normalizeAgentList(agents ?? previousLock?.agents);
613
+ const catalog = await loadAllSkills();
614
+ const installedSkillIds = previousLock?.skills || [];
615
+ const nativeHooks = collectNativeHooks({ catalog, skillIds: installedSkillIds });
616
+ const nativeHooksStatus = installedSkillIds.length > 0 ? "loaded" : "not-installed";
496
617
  const selectedNativeTargets = selectedAgents
497
618
  .map((agent) => NATIVE_ADAPTER_REGISTRY[agent])
498
619
  .filter((adapter) => adapter && adapter.supported)
@@ -505,7 +626,9 @@ export async function setupNativeProject({
505
626
  generatedAt,
506
627
  agents: selectedAgents,
507
628
  installRoot,
508
- nativeStatus: nativeStatusBefore
629
+ nativeStatus: nativeStatusBefore,
630
+ nativeHooks,
631
+ nativeHooksStatus
509
632
  };
510
633
 
511
634
  if (dryRun) {
@@ -558,7 +681,7 @@ export async function setupNativeProject({
558
681
  }
559
682
 
560
683
  const targetPath = resolveNativeAdapterTarget(cwd, adapter);
561
- const content = buildNativeRuleContent(agent, adapter);
684
+ const content = buildNativeRuleContent(agent, adapter, nativeHooks, nativeHooksStatus);
562
685
  await ensureManagedTextFile(targetPath, content, backupsDir, lockData, "managedNativeFiles");
563
686
  lockData.nativeProfiles[agent] = {
564
687
  status: "configured",
@@ -600,6 +723,7 @@ export async function installProject({
600
723
  excludeTags: parseTags(excludeTags)
601
724
  });
602
725
  const plan = buildInstallPlan({ cwd, detections, skills, agents: selectedAgents });
726
+ plan.decisionsRegistry = await planDecisionsRegistry(cwd);
603
727
 
604
728
  if (dryRun) {
605
729
  return { plan, applied: false };
@@ -621,6 +745,8 @@ export async function installProject({
621
745
  await mkdir(installRoot, { recursive: true });
622
746
  await mkdir(targetCatalogDir, { recursive: true });
623
747
  await mkdir(backupsDir, { recursive: true });
748
+ const decisionsRegistry = await ensureDecisionsRegistry(cwd);
749
+ plan.decisionsRegistry = decisionsRegistry;
624
750
 
625
751
  for (const skill of skills) {
626
752
  await copySkillTo(targetCatalogDir, skill.id);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skilly-hand/detectors",
3
- "version": "0.23.3",
3
+ "version": "0.25.0",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }