@booklib/skills 1.9.0 → 1.10.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/AGENTS.md CHANGED
@@ -1,108 +1,166 @@
1
1
  # Agent Integration
2
2
 
3
- How to install and use booklib-ai/skills with different AI coding assistants.
3
+ How to install and use `@booklib/skills` with different AI coding assistants.
4
4
 
5
- ## Claude Code
5
+ ## What gets installed
6
+
7
+ Each install creates up to three things in your project (or globally with `--global`):
8
+
9
+ | Directory | Contents | Purpose |
10
+ |-----------|----------|---------|
11
+ | `.claude/skills/` | 22 book-grounded skills | Auto-triggered by context |
12
+ | `.claude/commands/` | 22 slash commands | Explicit invocation (`/effective-python`) |
13
+ | `.claude/agents/` | 8 reviewer agents | Autonomous end-to-end reviews |
6
14
 
7
- Install all skills globally:
15
+ The fastest way to install is by **profile** — one command installs the right skills, commands, and agent for your language or domain:
8
16
 
9
17
  ```bash
10
- npx skills add booklib-ai/skills --all -g
18
+ npx @booklib/skills add --profile=python # Python
19
+ npx @booklib/skills add --profile=ts # TypeScript / JavaScript
20
+ npx @booklib/skills add --profile=jvm # Java + Kotlin + Spring Boot
21
+ npx @booklib/skills add --profile=rust # Rust
22
+ npx @booklib/skills add --profile=architecture # DDD, microservices, system design
23
+ npx @booklib/skills add --profile=data # Pipelines, ETL, storage
24
+ npx @booklib/skills add --profile=ui # UI design, charts, animations
25
+ npx @booklib/skills add --profile=lean # Lean Startup practices
26
+ npx @booklib/skills add --profile=core # Routing + general quality (good default)
27
+
28
+ # Or install everything
29
+ npx @booklib/skills add --all
11
30
  ```
12
31
 
13
- Install a single skill:
32
+ Add `--global` to any command to install to `~/.claude/` instead of the project directory.
33
+
34
+ ---
35
+
36
+ ## Claude Code
37
+
38
+ ### Install
14
39
 
15
40
  ```bash
16
- npx skills add booklib-ai/skills --skill clean-code-reviewer
41
+ # Recommended install by profile
42
+ npx @booklib/skills add --profile=ts --global
43
+
44
+ # Everything
45
+ npx @booklib/skills add --all --global
46
+
47
+ # Single skill
48
+ npx @booklib/skills add effective-typescript
17
49
  ```
18
50
 
19
- Skills are placed in `~/.claude/skills/` and available in every project. Claude Code picks them up automatically based on the `description` field in each `SKILL.md`.
51
+ ### How skills trigger
52
+
53
+ Claude Code reads skills from `.claude/skills/` (project) or `~/.claude/skills/` (global) and loads them based on the `description` field in each `SKILL.md`. Skills activate automatically when the context matches.
54
+
55
+ ### Slash commands
20
56
 
21
- To invoke a skill explicitly, use a slash command:
57
+ Each profile also installs companion slash commands:
22
58
 
23
59
  ```
24
- /clean-code-reviewer
60
+ /effective-typescript # runs the effective-typescript skill explicitly
61
+ /clean-code-reviewer # reviews against Clean Code principles
62
+ /skill-router # routes automatically to the best skill
25
63
  ```
26
64
 
27
- ## Cursor
65
+ ### Agents
28
66
 
29
- Install skills into your project:
67
+ Agents are autonomous reviewers installed to `.claude/agents/`. Invoke with `@`:
30
68
 
31
- ```bash
32
- npx skills add booklib-ai/skills --all
69
+ ```
70
+ @booklib-reviewer # auto-routes to the right skill
71
+ @python-reviewer # Python: effective-python + asyncio + scraping
72
+ @ts-reviewer # TypeScript: effective-typescript + clean-code
73
+ @jvm-reviewer # Java/Kotlin: effective-java + kotlin + spring-boot
74
+ @rust-reviewer # Rust: programming-with-rust + rust-in-action
75
+ @architecture-reviewer # DDD + microservices + system-design + DDIA
76
+ @data-reviewer # data-intensive-patterns + data-pipelines
77
+ @ui-reviewer # refactoring-ui + storytelling + animation
33
78
  ```
34
79
 
35
- Skills are placed in `.claude/skills/` in your project root. Cursor reads these when Agent mode is active.
80
+ ### Skill suggestion hook
36
81
 
37
- To trigger a skill, reference it by name in your prompt:
82
+ `add --all` also installs a `UserPromptSubmit` hook (`booklib-suggest.js`) that detects when you're asking to review code and suggests the relevant skill without firing on every message.
38
83
 
39
- ```
40
- Apply the effective-python skill to refactor this module.
84
+ To activate it, add the hook config to your Claude Code settings:
85
+ ```json
86
+ {
87
+ "UserPromptSubmit": [{
88
+ "hooks": [{ "type": "command", "command": "node \"$HOME/.claude/booklib-suggest.js\"" }]
89
+ }]
90
+ }
41
91
  ```
42
92
 
43
- ## GitHub Copilot (VS Code)
93
+ ---
94
+
95
+ ## Cursor
44
96
 
45
- Install skills globally:
97
+ Cursor reads rules from `.cursor/rules/`. Use `--target=cursor` to install there:
46
98
 
47
99
  ```bash
48
- npx skills add booklib-ai/skills --all -g
49
- ```
100
+ # Install to Cursor only
101
+ npx @booklib/skills add --profile=ts --target=cursor
50
102
 
51
- In VS Code with Copilot Chat, skills in `~/.claude/skills/` are available as context. Reference them explicitly in chat:
103
+ # Install to both Claude Code and Cursor
104
+ npx @booklib/skills add --profile=ts --target=all
52
105
 
53
- ```
54
- Using the design-patterns skill, review this class for pattern opportunities.
106
+ # Single skill to Cursor
107
+ npx @booklib/skills add effective-typescript --target=cursor
55
108
  ```
56
109
 
57
- ## Windsurf
110
+ Skills are written as `.cursor/rules/<skill-name>.md`. Cursor loads them in Agent mode. Agents are not applicable to Cursor (no native agent system).
58
111
 
59
- Install skills into your project:
112
+ ---
60
113
 
61
- ```bash
62
- npx skills add booklib-ai/skills --all
114
+ ## GitHub Copilot (VS Code)
115
+
116
+ Copilot Chat doesn't load `.claude/skills/` natively. Reference skills explicitly in chat:
117
+
118
+ ```
119
+ Using the effective-typescript skill, review this file for type safety issues.
120
+ Apply the clean-code-reviewer skill to the current diff.
63
121
  ```
64
122
 
65
- Skills are placed in `.claude/skills/`. In Windsurf's Cascade mode, you can reference a skill by name in your instructions or let the `skill-router` meta-skill select the right one automatically.
123
+ Or install globally and reference by name some Copilot extensions pick up `.claude/skills/` as context.
66
124
 
67
- ## skill-router — automatic routing
125
+ ---
68
126
 
69
- Instead of choosing a skill manually, install the `skill-router` meta-skill and let it pick:
127
+ ## Windsurf
128
+
129
+ Install into your project:
70
130
 
71
131
  ```bash
72
- npx skills add booklib-ai/skills --skill skill-router -g
132
+ npx @booklib/skills add --profile=ts
73
133
  ```
74
134
 
75
- Then prefix any task with:
135
+ Skills go to `.claude/skills/`. In Windsurf's Cascade mode, reference a skill by name or use `@booklib-reviewer` if agents are supported. The `skill-router` skill selects the right skill automatically when you describe your task.
76
136
 
77
- ```
78
- Route this task to the right skill, then apply it: [your request]
79
- ```
137
+ ---
80
138
 
81
- The router returns a ranked recommendation (primary + optional secondary) and applies it.
139
+ ## Supported platforms
82
140
 
83
- ## Manual installation
141
+ | Platform | Skills | Commands | Agents | Auto-trigger |
142
+ |----------|--------|----------|--------|--------------|
143
+ | Claude Code | `.claude/skills/` | `.claude/commands/` | `.claude/agents/` | Yes |
144
+ | Cursor | `.cursor/rules/` (`--target=cursor`) | — | — | Partial |
145
+ | GitHub Copilot | Manual reference | — | — | No |
146
+ | Windsurf | `.claude/skills/` | — | Partial | Partial |
84
147
 
85
- If your agent isn't listed above, copy skills directly:
148
+ ---
149
+
150
+ ## Manual installation
86
151
 
87
152
  ```bash
88
- # Single skill
89
- cp -r skills/effective-kotlin /path/to/project/.claude/skills/
153
+ # Single skill to any path
154
+ cp -r skills/effective-kotlin /path/to/.claude/skills/
90
155
 
91
156
  # All skills
92
- cp -r skills/* /path/to/project/.claude/skills/
157
+ cp -r skills/* /path/to/.claude/skills/
93
158
  ```
94
159
 
95
- Any agent that reads `.claude/skills/` will pick them up.
96
-
97
- ## Supported agents
160
+ Any agent that reads `.claude/skills/` picks them up automatically.
98
161
 
99
- | Agent | Install path | Auto-trigger | Manual trigger |
100
- |-------|-------------|--------------|----------------|
101
- | Claude Code | `~/.claude/skills/` or `.claude/skills/` | Yes | `/skill-name` |
102
- | Cursor | `.claude/skills/` | Partial | Reference by name |
103
- | GitHub Copilot | `~/.claude/skills/` | No | Reference by name |
104
- | Windsurf | `.claude/skills/` | Partial | Reference by name |
162
+ ---
105
163
 
106
- ## Requesting support for a new agent
164
+ ## Requesting support for a new platform
107
165
 
108
- Open an issue titled **"Agent Support: [Agent Name]"** and describe how the agent loads context files. We'll add installation instructions here.
166
+ Open an issue titled **"Platform Support: [Name]"** and describe how the platform loads context files. We'll add installation instructions here.
package/CONTRIBUTING.md CHANGED
@@ -135,6 +135,153 @@ PR checklist:
135
135
  - [ ] Pass rate ≥ 80% and delta ≥ 20pp in results.json
136
136
  - [ ] README.md skills table updated
137
137
 
138
+ ## Adding an Agent
139
+
140
+ An agent is a multi-step autonomous reviewer that orchestrates one or more skills. If you are packaging a single book's principles, write a skill. If you need to combine multiple skills, detect code patterns to route between them, or run a full review pipeline across a whole codebase, write an agent.
141
+
142
+ | Write a skill when... | Write an agent when... |
143
+ |-----------------------|------------------------|
144
+ | You are packaging one book's principles | You need two or more skills applied together |
145
+ | The logic is a single lens on code | You need routing logic (detect language → pick skill) |
146
+ | Instructions fit in one SKILL.md | You need a multi-step process (diff → detect → review → output) |
147
+
148
+ ### 1. Create the file
149
+
150
+ Agents live in a flat directory at the repo root:
151
+
152
+ ```
153
+ agents/<agent-name>.md
154
+ ```
155
+
156
+ The filename must be lowercase and hyphen-separated. It does not need a matching folder — unlike skills, agents have no `examples/` or `evals/` subdirectories.
157
+
158
+ ### 2. Write the frontmatter
159
+
160
+ Every agent file starts with YAML frontmatter:
161
+
162
+ ```markdown
163
+ ---
164
+ name: agent-name
165
+ description: >
166
+ When to invoke this agent and what it does. Include language names,
167
+ domain terms, and trigger conditions. Claude Code uses this field
168
+ for auto-invocation, so make it specific. Max 1024 characters.
169
+ tools: ["Read", "Grep", "Glob", "Bash"]
170
+ model: sonnet
171
+ ---
172
+ ```
173
+
174
+ **Required fields:**
175
+
176
+ - `name` — lowercase, hyphens only, matches filename exactly (without `.md`)
177
+ - `description` — used by Claude Code to decide when to invoke the agent automatically; include what it does, which skills it applies, and when to use it over alternatives
178
+ - `tools` — list of Claude Code tools the agent may call; `["Read", "Grep", "Glob", "Bash"]` covers most reviewers
179
+ - `model` — controls cost and capability (see model selection below)
180
+
181
+ ### 3. Write the body
182
+
183
+ A good agent body has five parts:
184
+
185
+ **Opening sentence** — one sentence identifying what the agent is, which books it draws from, and its scope.
186
+
187
+ **Process** — numbered steps the agent follows every time it runs:
188
+
189
+ 1. **Get the scope** — how to determine what to review (e.g., `git diff HEAD`, specific files passed by the user, or a directory scan)
190
+ 2. **Detect signals** — bash commands or grep patterns that route to the right skill(s)
191
+ 3. **Apply skill(s)** — one `### Step N` section per skill, each with `HIGH`/`MEDIUM`/`LOW` focus areas
192
+ 4. **Output** — the standard output format
193
+
194
+ **Detection table** — a Markdown table mapping code signals to skills:
195
+
196
+ ```markdown
197
+ | Code contains | Apply |
198
+ |---------------|-------|
199
+ | `async def`, `await`, `asyncio` | `using-asyncio-python` |
200
+ | `BeautifulSoup`, `scrapy` | `web-scraping-python` |
201
+ | General Python | `effective-python` |
202
+ ```
203
+
204
+ **Per-skill focus areas** — for each skill applied, list what to look for under `HIGH`, `MEDIUM`, and `LOW` headings. Pull these from the skills' own SKILL.md files, but trim to what is relevant for this agent's scope.
205
+
206
+ **Output format** — end the body with the standard output block:
207
+
208
+ ```markdown
209
+ ### Step N — Output format
210
+
211
+ ​```
212
+ **Skills applied:** `skill-name(s)`
213
+ **Scope:** [files reviewed]
214
+
215
+ ### HIGH
216
+ - `file:line` — finding
217
+
218
+ ### MEDIUM
219
+ - `file:line` — finding
220
+
221
+ ### LOW
222
+ - `file:line` — finding
223
+
224
+ **Summary:** X HIGH, Y MEDIUM, Z LOW findings.
225
+ ​```
226
+ ```
227
+
228
+ ### 4. Choose the right model
229
+
230
+ | Model | When to use |
231
+ |-------|-------------|
232
+ | `haiku` | Fast, cheap; use for simple or narrow tasks with a single skill and little routing logic |
233
+ | `sonnet` | Default for most reviewers; handles multi-skill routing and structured output well |
234
+ | `opus` | Only for architecture or reasoning-heavy agents where depth matters more than cost (e.g., `architecture-reviewer`) |
235
+
236
+ When in doubt, use `sonnet`.
237
+
238
+ ### 5. Follow naming conventions
239
+
240
+ | Pattern | Examples | Use for |
241
+ |---------|----------|---------|
242
+ | `<language>-reviewer` | `python-reviewer`, `jvm-reviewer`, `ts-reviewer` | Language-cluster agents combining all relevant skills for a language |
243
+ | `<domain>-reviewer` | `architecture-reviewer`, `data-reviewer`, `ui-reviewer` | Domain-cluster agents cutting across languages |
244
+ | Descriptive name | `booklib-reviewer` | Meta or router agents that don't fit a single language or domain |
245
+
246
+ ### 6. Installation
247
+
248
+ Agents install to `.claude/agents/` alongside skills:
249
+
250
+ ```bash
251
+ # Install one agent
252
+ npx skills add booklib-ai/skills --agent=python-reviewer
253
+
254
+ # Install everything (skills + agents)
255
+ npx skills add booklib-ai/skills --all
256
+ ```
257
+
258
+ Once installed, Claude Code reads the agent's `description` field and auto-invokes it when a matching request arrives — no slash command needed.
259
+
260
+ ### 7. No eval system (yet)
261
+
262
+ There is no `evals/` system for agents. Instead:
263
+
264
+ - Make the `description` accurate — it controls when the agent auto-invokes
265
+ - Check that every `### Step N` section has a clear, testable action
266
+ - Test manually: install the agent locally and run it against a real codebase
267
+
268
+ ### 8. Submit a PR
269
+
270
+ ```bash
271
+ git checkout -b agent/agent-name
272
+ git add agents/agent-name.md
273
+ git commit -m "feat: add agent-name agent"
274
+ gh pr create --title "feat: add agent-name agent" --body "..."
275
+ ```
276
+
277
+ PR checklist:
278
+ - [ ] Filename matches `name` in frontmatter
279
+ - [ ] `description` is under 1024 characters and describes when to invoke it
280
+ - [ ] `model` is appropriate for the agent's complexity
281
+ - [ ] Process steps are numbered and each has a clear action
282
+ - [ ] Detection table covers the signals the agent handles
283
+ - [ ] Output format section matches the standard `HIGH`/`MEDIUM`/`LOW` format
284
+
138
285
  ## Requesting a skill
139
286
 
140
287
  Open an issue titled **"Skill Request: [Book Name]"** and describe why the book would make a good skill. Community members can then pick it up.
package/PLAN.md CHANGED
@@ -1,100 +1,28 @@
1
1
  # Implementation Plan
2
2
 
3
- Current version: **1.8.0**
4
- Next release: **1.9.0**
3
+ Current version: **1.10.0**
5
4
 
6
- ## Remaining features (priority order)
5
+ ## Completed in 1.9.0
7
6
 
8
- ---
7
+ - `skills agents` list command
8
+ - Cursor support (`--target=cursor` / `--target=all`)
9
+ - Hooks: `hooks/suggest.js` + `hooks/hooks.json`
10
+ - README overhaul (three-tier architecture)
11
+ - AGENTS.md rewrite
9
12
 
10
- ### 1. `skills agents` list command
11
- **File:** `bin/skills.js`
12
- **What:** New `agents` command that lists all agents from `agents/` with name + description (parsed from frontmatter). Mirrors `skills list`.
13
- **Usage:**
14
- ```bash
15
- skills agents
16
- skills agents --info booklib-reviewer
17
- ```
13
+ ## Completed in 1.10.0
18
14
 
19
- ---
15
+ - Rules system: `rules/{language}/*.md` always-on standards files
16
+ - `skills add --rules` / `skills add --rules=<language>` installs to `.claude/rules/`
17
+ - `skills rules` list command
18
+ - `skills add --hooks` standalone flag (previously hooks only installed via `--all`)
19
+ - CONTRIBUTING.md: "Adding an Agent" section
20
+ - `--all` now also installs all rules
20
21
 
21
- ### 2. Cursor support (`--target`)
22
- **File:** `bin/skills.js`
23
- **What:** `--target` flag on `add` that writes skills to `.cursor/rules/` (Cursor's rule system). Skills install as rule files; agents not applicable to Cursor (no native agent system).
24
- **Usage:**
25
- ```bash
26
- skills add --profile=ts --target cursor # writes to .cursor/rules/
27
- skills add --profile=ts --target all # writes to both .claude/ and .cursor/rules/
28
- skills add effective-python --target cursor
29
- ```
30
- **Cursor paths:**
31
- - Skills → `.cursor/rules/<skill-name>.md` (copy of SKILL.md)
32
- - Commands → not applicable
33
- - Agents → not applicable
22
+ ## Possible next steps
34
23
 
35
- ---
36
-
37
- ### 3. `hooks/` UserPromptSubmit skill suggestion
38
- **Files:** `hooks/hooks.json`, `hooks/suggest.js`
39
- **What:** A single `UserPromptSubmit` hook. Reads the user's prompt, detects language + "review/check/improve/refactor" intent, outputs a one-line skill suggestion. Only fires when both intent AND a language signal are present — not on every message.
40
-
41
- **Hook config:**
42
- ```json
43
- {
44
- "UserPromptSubmit": [{
45
- "matcher": ".*",
46
- "hooks": [{ "type": "command", "command": "node ~/.claude/skills/booklib-suggest.js" }]
47
- }]
48
- }
49
- ```
50
-
51
- **suggest.js logic:**
52
- - Read prompt from stdin (JSON event from Claude Code)
53
- - Check for review intent: `review|check|improve|refactor|fix|audit`
54
- - Check for language signals: `.py`, `.ts`, `.tsx`, `.java`, `.kt`, `.rs`, etc.
55
- - Output one-line suggestion or nothing
56
-
57
- **Install path:** `hooks/suggest.js` in repo → installed to `.claude/` root as `booklib-suggest.js` via `skills add --all` or `skills add --hooks`.
58
-
59
- ---
60
-
61
- ### 4. README overhaul
62
- **File:** `README.md`
63
- **What:** Rewrite to document the full three-tier architecture. Current README only describes skills. Needs: profiles section, agents section, commands section, architecture diagram.
64
-
65
- **New structure:**
66
- ```
67
- 1. Tagline + install
68
- 2. Three-tier architecture diagram (skills → commands → agents → profiles)
69
- 3. Quick start (pick a profile)
70
- 4. Skills list (existing)
71
- 5. Agents (new section)
72
- 6. Profiles (new section)
73
- 7. Commands (new section — brief, link to commands/)
74
- 8. Quality / evals (existing, improved)
75
- 9. Contributing
76
- ```
77
-
78
- ---
79
-
80
- ## Parallel implementation tracks
81
-
82
- | Track | Files touched | Depends on |
83
- |-------|--------------|------------|
84
- | A | `bin/skills.js` | — |
85
- | B | `hooks/hooks.json`, `hooks/suggest.js` | — |
86
- | C | `README.md` | — |
87
-
88
- Tracks B and C are independent and can be implemented simultaneously.
89
- Track A (`bin/skills.js`) has no file conflicts with B or C.
90
- All three can be implemented in parallel.
91
-
92
- ---
93
-
94
- ## Release checklist
95
-
96
- - [ ] Track A: `skills agents` command + Cursor support in bin/skills.js
97
- - [ ] Track B: hooks/hooks.json + hooks/suggest.js
98
- - [ ] Track C: README overhaul
99
- - [ ] Bump version to 1.9.0
100
- - [ ] Commit + tag v1.9.0 + push
24
+ - `skills add --profile=<name> --rules` to install profile + relevant rules together
25
+ - Profile-aware rules: each profile installs matching rules automatically
26
+ - `skills rules --info=<language>` for detailed view
27
+ - Rules for more languages (Go, Swift, C++)
28
+ - Agent evals system
package/bin/skills.js CHANGED
@@ -12,6 +12,7 @@ const command = args[0];
12
12
  const skillsRoot = path.join(__dirname, '..', 'skills');
13
13
  const commandsRoot = path.join(__dirname, '..', 'commands');
14
14
  const agentsRoot = path.join(__dirname, '..', 'agents');
15
+ const rulesRoot = path.join(__dirname, '..', 'rules');
15
16
 
16
17
  // ─── Installation profiles ────────────────────────────────────────────────────
17
18
  const PROFILES = {
@@ -149,6 +150,9 @@ const commandsTargetDir = isGlobal
149
150
  const agentsTargetDir = isGlobal
150
151
  ? path.join(os.homedir(), '.claude', 'agents')
151
152
  : path.join(process.cwd(), '.claude', 'agents');
153
+ const rulesTargetDir = isGlobal
154
+ ? path.join(os.homedir(), '.claude', 'rules')
155
+ : path.join(process.cwd(), '.claude', 'rules');
152
156
 
153
157
  function copyCommand(skillName) {
154
158
  const src = path.join(commandsRoot, `${skillName}.md`);
@@ -221,6 +225,42 @@ function copyHooks() {
221
225
  }
222
226
  }
223
227
 
228
+ function getAvailableRules() {
229
+ // Returns [{language, name, file}] for each rule file found under rules/
230
+ if (!fs.existsSync(rulesRoot)) return [];
231
+ const result = [];
232
+ for (const lang of fs.readdirSync(rulesRoot).sort()) {
233
+ const langDir = path.join(rulesRoot, lang);
234
+ if (!fs.statSync(langDir).isDirectory()) continue;
235
+ for (const file of fs.readdirSync(langDir).filter(f => f.endsWith('.md')).sort()) {
236
+ result.push({ language: lang, name: file.replace(/\.md$/, ''), file: path.join(langDir, file) });
237
+ }
238
+ }
239
+ return result;
240
+ }
241
+
242
+ function copyRules(language) {
243
+ // Copies all rule files for a given language (or 'common') to rulesTargetDir
244
+ const langDir = path.join(rulesRoot, language);
245
+ if (!fs.existsSync(langDir)) {
246
+ console.error(c.red(`✗ No rules for language "${language}".`) + ' Run ' + c.cyan('skills rules') + ' to see available rules.');
247
+ process.exit(1);
248
+ }
249
+ const destDir = path.join(rulesTargetDir, language);
250
+ fs.mkdirSync(destDir, { recursive: true });
251
+ for (const file of fs.readdirSync(langDir).filter(f => f.endsWith('.md'))) {
252
+ const dest = path.join(destDir, file);
253
+ fs.copyFileSync(path.join(langDir, file), dest);
254
+ console.log(c.green('✓') + ` ${c.bold(language + '/' + file.replace(/\.md$/, ''))} rule → ${c.dim(dest)}`);
255
+ }
256
+ }
257
+
258
+ function copyAllRules() {
259
+ const rules = getAvailableRules();
260
+ const languages = [...new Set(rules.map(r => r.language))];
261
+ for (const lang of languages) copyRules(lang);
262
+ }
263
+
224
264
  function copySkillToCursor(skillName) {
225
265
  const src = path.join(skillsRoot, skillName, 'SKILL.md');
226
266
  if (!fs.existsSync(src)) return;
@@ -825,15 +865,18 @@ async function main() {
825
865
  }
826
866
 
827
867
  case 'add': {
828
- const addAll = args.includes('--all');
829
- const noCommands = args.includes('--no-commands');
830
- const noAgents = args.includes('--no-agents');
831
- const agentArg = args.find(a => a.startsWith('--agent='))?.split('=')[1];
832
- const profileArg = args.find(a => a.startsWith('--profile='))?.split('=')[1];
833
- const targetArg = (args.find(a => a.startsWith('--target='))?.split('=')[1] ?? 'claude').toLowerCase();
834
- const toClaude = targetArg === 'claude' || targetArg === 'all';
835
- const toCursor = targetArg === 'cursor' || targetArg === 'all';
836
- const skillName = args.find(a => !a.startsWith('--') && a !== 'add');
868
+ const addAll = args.includes('--all');
869
+ const addHooks = args.includes('--hooks');
870
+ const noCommands = args.includes('--no-commands');
871
+ const noAgents = args.includes('--no-agents');
872
+ const agentArg = args.find(a => a.startsWith('--agent='))?.split('=')[1];
873
+ const profileArg = args.find(a => a.startsWith('--profile='))?.split('=')[1];
874
+ const rulesArg = args.find(a => a === '--rules' || a.startsWith('--rules='));
875
+ const rulesLang = rulesArg?.includes('=') ? rulesArg.split('=')[1] : null;
876
+ const targetArg = (args.find(a => a.startsWith('--target='))?.split('=')[1] ?? 'claude').toLowerCase();
877
+ const toClaude = targetArg === 'claude' || targetArg === 'all';
878
+ const toCursor = targetArg === 'cursor' || targetArg === 'all';
879
+ const skillName = args.find(a => !a.startsWith('--') && a !== 'add');
837
880
 
838
881
  const installSkills = (list) => {
839
882
  if (toClaude) list.forEach(s => copySkill(s, targetDir));
@@ -868,12 +911,25 @@ async function main() {
868
911
  console.log(c.dim(`\nInstalled to ${agentsTargetDir}`));
869
912
  } else if (addAll) {
870
913
  const skills = getAvailableSkills();
914
+ const agents = getAvailableAgents();
871
915
  installSkills(skills);
872
- installAgents(getAvailableAgents());
873
- if (toClaude) copyHooks();
874
- const agentCount = (!noAgents && toClaude) ? getAvailableAgents().length : 0;
916
+ installAgents(agents);
917
+ if (toClaude) { copyHooks(); copyAllRules(); }
918
+ const agentCount = (!noAgents && toClaude) ? agents.length : 0;
875
919
  const targets = [toClaude && '.claude', toCursor && '.cursor/rules'].filter(Boolean).join(' + ');
876
- console.log(c.dim(`\nInstalled ${skills.length} skills, ${agentCount} agents → ${targets}`));
920
+ console.log(c.dim(`\nInstalled ${skills.length} skills, ${agentCount} agents, ${getAvailableRules().length} rules → ${targets}`));
921
+ } else if (addHooks) {
922
+ if (toClaude) copyHooks();
923
+ else console.log(c.yellow(' --hooks only applies to Claude targets. Use without --target=cursor.'));
924
+ break;
925
+ } else if (rulesArg) {
926
+ if (!toClaude) {
927
+ console.log(c.yellow(' --rules only applies to Claude targets (.claude/rules/).'));
928
+ break;
929
+ }
930
+ if (rulesLang) copyRules(rulesLang);
931
+ else copyAllRules();
932
+ console.log(c.dim(`\nInstalled rules → ${rulesTargetDir}`));
877
933
  } else if (skillName) {
878
934
  installSkills([skillName]);
879
935
  console.log(c.dim(`\nInstalled to ${targetDir}`));
@@ -1019,6 +1075,37 @@ async function main() {
1019
1075
  break;
1020
1076
  }
1021
1077
 
1078
+ case 'rules': {
1079
+ const available = getAvailableRules();
1080
+ if (!available.length) {
1081
+ console.log(c.yellow(' No rules found.'));
1082
+ break;
1083
+ }
1084
+ // Group by language
1085
+ const byLang = {};
1086
+ for (const r of available) {
1087
+ if (!byLang[r.language]) byLang[r.language] = [];
1088
+ byLang[r.language].push(r);
1089
+ }
1090
+ console.log('');
1091
+ console.log(c.bold(' @booklib/skills — rules') + c.dim(` (${available.length} always-on)`));
1092
+ console.log(' ' + c.line(60));
1093
+ for (const [lang, rules] of Object.entries(byLang)) {
1094
+ console.log(` ${c.bold(lang)}`);
1095
+ for (const r of rules) {
1096
+ const content = fs.readFileSync(r.file, 'utf8');
1097
+ const descMatch = content.match(/^description:\s*(.+)$/m);
1098
+ const desc = descMatch ? descMatch[1].trim().replace(/^>$/, '') : '';
1099
+ console.log(` ${c.cyan(r.name.padEnd(28))}${c.dim(firstSentence(desc, 55))}`);
1100
+ }
1101
+ console.log('');
1102
+ }
1103
+ console.log(c.dim(` skills add --rules install all rules → .claude/rules/`));
1104
+ console.log(c.dim(` skills add --rules=<language> install rules for one language`));
1105
+ console.log('');
1106
+ break;
1107
+ }
1108
+
1022
1109
  case 'profiles': {
1023
1110
  const nameW = Math.max(...Object.keys(PROFILES).map(k => k.length)) + 2;
1024
1111
  console.log('');
@@ -1045,13 +1132,17 @@ ${c.bold(' Usage:')}
1045
1132
  ${c.cyan('skills agents')} list all available agents
1046
1133
  ${c.cyan('skills agents')} ${c.dim('--info=<name>')} full description of an agent
1047
1134
  ${c.cyan('skills profiles')} list available profiles
1135
+ ${c.cyan('skills rules')} list always-on rule files
1048
1136
  ${c.cyan('skills info')} ${c.dim('<name>')} full description of a skill
1049
1137
  ${c.cyan('skills demo')} ${c.dim('<name>')} before/after example
1050
1138
  ${c.cyan('skills add')} ${c.dim('--profile=<name>')} install a profile (skills + commands + agent)
1051
1139
  ${c.cyan('skills add')} ${c.dim('<name>')} install a single skill + /command
1052
- ${c.cyan('skills add --all')} install everything (skills + commands + agents)
1140
+ ${c.cyan('skills add --all')} install everything (skills + agents + rules + hooks)
1053
1141
  ${c.cyan('skills add')} ${c.dim('<name> --global')} install globally (~/.claude/)
1054
1142
  ${c.cyan('skills add')} ${c.dim('--agent=<name>')} install a single agent to .claude/agents/
1143
+ ${c.cyan('skills add --rules')} install always-on rules to .claude/rules/
1144
+ ${c.cyan('skills add')} ${c.dim('--rules=<language>')} install rules for one language
1145
+ ${c.cyan('skills add --hooks')} install the UserPromptSubmit suggestion hook
1055
1146
  ${c.cyan('skills add')} ${c.dim('--target=cursor')} install to .cursor/rules/ (Cursor IDE)
1056
1147
  ${c.cyan('skills add')} ${c.dim('--target=all')} install to both .claude/ and .cursor/
1057
1148
  ${c.cyan('skills add')} ${c.dim('--no-commands')} skip /command installation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@booklib/skills",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Book knowledge distilled into structured AI skills for Claude Code and other AI assistants",
5
5
  "bin": {
6
6
  "skills": "bin/skills.js"
@@ -0,0 +1,42 @@
1
+ ---
2
+ description: Always-on Clean Code standards from Robert C. Martin. Apply to all code regardless of language.
3
+ ---
4
+
5
+ # Clean Code Standards
6
+
7
+ Apply these principles from *Clean Code* (Robert C. Martin) to all code you write or review.
8
+
9
+ ## Names
10
+
11
+ - Use intention-revealing names — if the name needs a comment to explain it, rename it
12
+ - Avoid abbreviations unless universally understood (`url`, `id`, `ctx` are fine; `mgr`, `proc` are not)
13
+ - Classes and types are nouns; methods and functions are verb phrases
14
+ - Avoid noise words that add no meaning: `Manager`, `Data`, `Info`, `Handler` in type names usually signal a missing concept
15
+ - Boolean variables and functions read as assertions: `isEnabled`, `hasPermission`, `canRetry`
16
+
17
+ ## Functions
18
+
19
+ - Functions do one thing; if you can extract a meaningful sub-function with a non-trivial name, the function does too much
20
+ - Keep functions short — aim for under 20 lines; over 40 is a smell
21
+ - Max 3 parameters; group related parameters into a value object when you need more
22
+ - Avoid boolean flag parameters — they signal the function does two things; split it
23
+ - No side effects in functions that return values
24
+
25
+ ## Comments
26
+
27
+ - Comments compensate for failure to express intent in code — prefer renaming over commenting
28
+ - Never commit commented-out code; use version control
29
+ - `// TODO:` is acceptable only when tracked in an issue; delete stale TODOs
30
+ - Document *why*, not *what* — the code shows what; the comment explains a non-obvious reason
31
+
32
+ ## Structure
33
+
34
+ - Group related code together; put high-level concepts at the top, details below
35
+ - Functions in a file should be ordered so callers appear before callees
36
+ - Avoid deep nesting — if `if`/`else` chains exceed 3 levels, extract or invert conditions
37
+
38
+ ## Error handling
39
+
40
+ - Prefer exceptions over error codes for exceptional conditions
41
+ - Handle errors at the appropriate abstraction level — don't catch and re-throw unless you add context
42
+ - Never swallow exceptions silently; at minimum log before ignoring
@@ -0,0 +1,42 @@
1
+ ---
2
+ description: Always-on Effective Java standards from Joshua Bloch. Apply when writing or reviewing Java code.
3
+ ---
4
+
5
+ # Effective Java Standards
6
+
7
+ Apply these principles from *Effective Java* (Joshua Bloch, 3rd edition) to all Java code.
8
+
9
+ ## Object creation
10
+
11
+ - Prefer static factory methods over constructors — they have names, can return subtypes, and can cache instances
12
+ - Use a builder when a constructor or factory would have more than 3 parameters
13
+ - Never create unnecessary objects; reuse `String` literals, prefer `Boolean.valueOf(x)` over `new Boolean(x)`
14
+
15
+ ## Classes and mutability
16
+
17
+ - Minimize mutability — all fields `private final` by default; add setters only when needed
18
+ - Favor composition over inheritance; explicitly document classes designed for extension or mark them `final`
19
+ - Override `@Override` on every method that overrides or implements; the annotation catches typos at compile time
20
+
21
+ ## Methods
22
+
23
+ - Validate parameters at entry; throw `IllegalArgumentException`, `NullPointerException`, or `IndexOutOfBoundsException` with a message
24
+ - Return empty collections or `Optional`, never `null`, from methods with a non-primitive return type
25
+ - Use `Optional` for return values that may be absent; don't use it for fields or parameters
26
+
27
+ ## Exceptions
28
+
29
+ - Use checked exceptions for recoverable conditions; unchecked (`RuntimeException`) for programming errors
30
+ - Prefer standard exceptions: `IllegalArgumentException`, `IllegalStateException`, `UnsupportedOperationException`, `NullPointerException`
31
+ - Don't swallow exceptions — at minimum log with context before ignoring; never `catch (Exception e) {}`
32
+
33
+ ## Generics and collections
34
+
35
+ - Use generic types and methods; avoid raw types (`List` → `List<E>`)
36
+ - Use bounded wildcards (`? extends T` for producers, `? super T` for consumers — PECS)
37
+ - Prefer `List` over arrays for type safety; use arrays only for performance-sensitive low-level code
38
+
39
+ ## Concurrency
40
+
41
+ - Synchronize all accesses to shared mutable state; prefer `java.util.concurrent` utilities over `synchronized`
42
+ - Prefer immutable objects and thread confinement over shared mutable state
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Always-on Effective Kotlin standards from Marcin Moskała. Apply when writing or reviewing Kotlin code.
3
+ ---
4
+
5
+ # Effective Kotlin Standards
6
+
7
+ Apply these principles from *Effective Kotlin* (Marcin Moskała, 2nd edition) to all Kotlin code.
8
+
9
+ ## Safety
10
+
11
+ - Prefer `val` over `var`; use `var` only when mutation is genuinely required
12
+ - Use nullable types explicitly (`T?`); avoid `!!` — narrow with `?.`, `?:`, `let`, or `checkNotNull()`
13
+ - Use `require()` for argument preconditions and `check()` for state preconditions at function entry
14
+
15
+ ## Functions
16
+
17
+ - Use named arguments when passing more than 2 parameters, especially when they share the same type
18
+ - Use default arguments instead of overloads for optional behavior
19
+ - Prefer extension functions over utility classes for domain operations on a type you own
20
+
21
+ ## Classes and design
22
+
23
+ - Use data classes for value objects — they get `equals`, `hashCode`, `copy`, and `toString` for free
24
+ - Prefer sealed classes over open hierarchies when the set of subtypes is finite and known
25
+ - Use `object` for singletons, `companion object` for factory methods and class-level constants
26
+
27
+ ## Collections
28
+
29
+ - Use functional operators (`map`, `filter`, `fold`, `groupBy`) over manual loops
30
+ - Prefer `Sequence` for large collections or multi-step pipelines — avoids intermediate lists
31
+ - Use `buildList { }` / `buildMap { }` instead of a mutable variable followed by `.toList()`
32
+
33
+ ## Coroutines
34
+
35
+ - Launch coroutines in a structured `CoroutineScope`; never use `GlobalScope` in production
36
+ - Use `withContext(Dispatchers.IO)` for blocking I/O; never block the main/UI thread
37
+ - Prefer `Flow` over callbacks for asynchronous streams; use `StateFlow` for observable state
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Always-on Effective Python standards from Brett Slatkin. Apply when writing or reviewing Python code.
3
+ ---
4
+
5
+ # Effective Python Standards
6
+
7
+ Apply these principles from *Effective Python* (Brett Slatkin, 3rd edition) to all Python code.
8
+
9
+ ## Pythonic style
10
+
11
+ - Use `enumerate()` over `range(len(...))` for indexed iteration
12
+ - Use f-strings for interpolation; avoid `%` formatting and `.format()`
13
+ - Prefer unpacking over indexing: `first, *rest = items` instead of `items[0]` and `items[1:]`
14
+ - Use `zip()` to iterate two sequences together; use `zip(strict=True)` when lengths must match
15
+
16
+ ## Data structures
17
+
18
+ - Use `list` for ordered mutable sequences, `tuple` for immutable positional data, `set` for membership tests
19
+ - Use `collections.defaultdict` or `Counter` instead of manual dict initialization
20
+ - Prefer `dataclasses` over plain dicts or namedtuples for structured data with methods
21
+
22
+ ## Functions
23
+
24
+ - Use keyword-only arguments (`def f(a, *, b)`) for optional parameters that benefit from names at the call site
25
+ - Never use mutable default arguments — use `None` and assign inside the function body
26
+ - Prefer generator expressions `(x for x in ...)` over list comprehensions when you don't need the full list in memory
27
+
28
+ ## Type annotations
29
+
30
+ - Annotate all public functions and class attributes
31
+ - Use `X | None` (Python 3.10+) or `Optional[X]` for nullable types; never return `None` silently from a typed function
32
+ - Avoid `Any` except at system boundaries (external APIs, deserialized JSON)
33
+
34
+ ## Error handling
35
+
36
+ - Catch specific exception types; never use bare `except:`
37
+ - Use `contextlib.suppress(ExceptionType)` for intentionally ignored exceptions — makes the intent explicit
38
+ - Use `__all__` in every module to declare its public API
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Always-on Rust standards from Programming with Rust and Rust in Action. Apply when writing or reviewing Rust code.
3
+ ---
4
+
5
+ # Rust Standards
6
+
7
+ Apply these principles from *Programming with Rust* (Donis Marshall) and *Rust in Action* (Tim McNamara) to all Rust code.
8
+
9
+ ## Ownership and borrowing
10
+
11
+ - Use owned values (`String`, `Vec<T>`) for data you own; borrow (`&str`, `&[T]`) when you only need to read
12
+ - Prefer passing `&T` or `&mut T` over cloning; clone only when ownership transfer is required
13
+ - Use `Rc<T>` for single-threaded shared ownership, `Arc<T>` for multi-threaded; use `RefCell<T>` / `Mutex<T>` for interior mutability
14
+
15
+ ## Error handling
16
+
17
+ - Return `Result<T, E>` from all fallible functions; propagate with `?`
18
+ - Use `thiserror` to define library errors with `#[derive(Error)]`; use `anyhow` for application-level error context
19
+ - Avoid `.unwrap()` in library code; use `.expect("clear message")` in application code where panicking is intentional
20
+
21
+ ## Types and traits
22
+
23
+ - Use `struct` for data, `enum` for variants with payloads, `trait` for shared behaviour
24
+ - Implement standard traits where appropriate: `Debug` always, `Display` for user-facing types, `Clone`, `PartialEq`, `Hash` as needed
25
+ - Use `impl Trait` in argument position for static dispatch; `Box<dyn Trait>` only when you need runtime dispatch
26
+
27
+ ## Idiomatic patterns
28
+
29
+ - Use `Iterator` adapters (`map`, `filter`, `flat_map`, `collect`) over manual loops — the compiler optimizes them equally
30
+ - Use `Option` methods (`map`, `unwrap_or`, `and_then`, `ok_or`) over `match` for simple transformations
31
+ - Use `if let` for single-variant matching; use `match` for exhaustive handling
32
+
33
+ ## Naming and style
34
+
35
+ - Types: `PascalCase`; functions, variables, modules: `snake_case`; constants and statics: `SCREAMING_SNAKE_CASE`
36
+ - Lifetime names: `'a`, `'b` for simple cases; descriptive names (`'arena`, `'cx`) for complex lifetimes
37
+ - Mark all public items in a library crate with doc comments (`///`)
@@ -0,0 +1,42 @@
1
+ ---
2
+ description: Always-on Effective TypeScript standards from Dan Vanderkam. Apply when writing or reviewing TypeScript or JavaScript code.
3
+ ---
4
+
5
+ # Effective TypeScript Standards
6
+
7
+ Apply these principles from *Effective TypeScript* (Dan Vanderkam, 2nd edition) to all TypeScript code.
8
+
9
+ ## Types
10
+
11
+ - Prefer union types over enums for simple sets of values: `type Direction = 'N' | 'S' | 'E' | 'W'`
12
+ - Use `interface` for extensible object shapes that others may augment; use `type` for unions, intersections, and computed types
13
+ - Avoid `any`; use `unknown` when the type is genuinely unknown, then narrow with guards before use
14
+ - Avoid type assertions (`as T`) — prefer type narrowing, overloads, or generics
15
+
16
+ ## Type inference
17
+
18
+ - Let TypeScript infer return types on internal functions; explicitly annotate public API return types
19
+ - Annotate a variable at declaration if it cannot be initialized immediately
20
+ - Use `as const` to preserve literal types; don't use it just to silence widening errors
21
+
22
+ ## Null safety
23
+
24
+ - Enable `strict` mode (which includes `strictNullChecks`) — treat every `T | undefined` as requiring explicit handling
25
+ - Use optional chaining `?.` and nullish coalescing `??` over `&&` and `||` chains
26
+ - Never use non-null assertion (`!`) — narrow instead
27
+
28
+ ## Structural typing
29
+
30
+ - TypeScript checks shapes, not nominal types — understand that duck typing applies
31
+ - Use discriminated unions with a `kind` or `type` literal field for exhaustive `switch` / narrowing
32
+ - Avoid class hierarchies for data shapes — prefer interfaces and composition
33
+
34
+ ## Generics
35
+
36
+ - Constrain generics to the minimum required: `<T extends string>` not `<T>`
37
+ - Use descriptive generic names for complex types (`<TItem, TKey>`) and single letters for simple transforms (`<T>`, `<K, V>`)
38
+
39
+ ## Functions
40
+
41
+ - Prefer function overloads over union parameter types to express the relationship between input and output
42
+ - Keep functions pure where possible; extract side effects to the call site