Skip to content

Commit 712bdae

Browse files
rjmurillo-botclaude
andcommitted
refactor(skillbook): enforce ONE skill format, remove bundled option
BREAKING: Eliminate Format A/B decision tree. All skills use atomic format. Changes: - Update skillbook agent docs (claude, copilot-cli, vs-code-agents) - Update shared template with simplified format section - Delete skill-format-selection-decision-tree.md memory - Remove entry from skills-documentation-index.md - Create Validate-SkillFormat.ps1 script - Add skill format enforcement to pre-commit hook The new format requirement: - ONE skill per file. No bundled skills. No exceptions. - Pre-commit blocks new bundled-format skill files - Legacy bundled files remain (non-blocking warning) Strong opinion: Consistency over complexity. One format always. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a8edfeb commit 712bdae

File tree

8 files changed

+180
-434
lines changed

8 files changed

+180
-434
lines changed

.githooks/pre-commit

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,42 @@ else
683683
echo_info "No memory files staged. Skipping memory index validation."
684684
fi
685685

686+
#
687+
# Skill Format Validation (BLOCKING for new files)
688+
#
689+
# Enforces ADR-017 atomic format: ONE skill per file. No bundled skills.
690+
# Blocks commits that add new bundled-format skill files.
691+
# Legacy bundled files are allowed (non-blocking warning only).
692+
#
693+
# Related: ADR-017, Issue #307
694+
#
695+
SKILL_FORMAT_SCRIPT="$REPO_ROOT/scripts/Validate-SkillFormat.ps1"
696+
697+
if [ -n "$STAGED_MEMORY_FILES" ]; then
698+
echo_info "Checking skill format (ADR-017: one skill per file)..."
699+
700+
# MEDIUM-002: Reject symlinks for security
701+
if [ -L "$SKILL_FORMAT_SCRIPT" ]; then
702+
echo_warning "Skipping skill format validation: script path is a symlink"
703+
elif [ -f "$SKILL_FORMAT_SCRIPT" ]; then
704+
if command -v pwsh &> /dev/null; then
705+
# Run skill format validation on staged files only
706+
# -StagedOnly checks only new/modified files (not legacy bundled files)
707+
if ! pwsh -NoProfile -File "$SKILL_FORMAT_SCRIPT" -StagedOnly -CI 2>&1; then
708+
echo_error "Skill format validation FAILED."
709+
echo_info " ADR-017 requires ONE skill per file. Split bundled skills."
710+
EXIT_STATUS=1
711+
else
712+
echo_success "Skill format validation: PASS"
713+
fi
714+
else
715+
echo_warning "PowerShell not available. Skipping skill format validation."
716+
fi
717+
else
718+
echo_info "Skill format validation script not found. Skipping."
719+
fi
720+
fi
721+
686722
#
687723
# Final Summary
688724
#

.serena/memories/skill-format-selection-decision-tree.md

Lines changed: 0 additions & 66 deletions
This file was deleted.

.serena/memories/skills-documentation-index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@
44
| fallback tool call graceful degradation mcp serena | documentation-fallback-pattern |
55
| user-facing content internal PR issue session exclude | documentation-user-facing |
66
| self-contained artifact handoff agent amnesia autonomous | documentation-self-contained |
7-
| skill format standalone bundled decision tree mermaid P0 | skill-format-selection-decision-tree |
87
| index selection domain routing keyword overlap create new | skill-index-selection-decision-tree |
98
| verification critic amnesiac completeness objective PASS FAIL protocol | documentation-verification-protocol |

scripts/Validate-SkillFormat.ps1

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<#
2+
.SYNOPSIS
3+
Validates skill files follow the atomic format (one skill per file).
4+
5+
.DESCRIPTION
6+
Enforces ADR-017 skill format requirements:
7+
- One skill per file (no bundled skills)
8+
- Files with `## Skill-` headers are flagged as bundled format
9+
10+
This validation runs on staged .serena/memories/ files during pre-commit.
11+
12+
.PARAMETER Path
13+
Path to the memories directory. Defaults to .serena/memories/.
14+
15+
.PARAMETER CI
16+
Run in CI mode (stricter output, exit codes).
17+
18+
.PARAMETER StagedOnly
19+
Only check staged files (for pre-commit hook).
20+
21+
.EXAMPLE
22+
pwsh scripts/Validate-SkillFormat.ps1
23+
24+
.EXAMPLE
25+
pwsh scripts/Validate-SkillFormat.ps1 -StagedOnly
26+
27+
.NOTES
28+
Related: ADR-017, Issue #307
29+
#>
30+
[CmdletBinding()]
31+
param(
32+
[string]$Path = ".serena/memories",
33+
[switch]$CI,
34+
[switch]$StagedOnly
35+
)
36+
37+
$ErrorActionPreference = 'Stop'
38+
$script:ExitCode = 0
39+
$script:BundledFiles = @()
40+
41+
# Get files to check
42+
if ($StagedOnly) {
43+
# Get staged memory files from git
44+
$stagedFiles = git diff --cached --name-only --diff-filter=ACMR 2>$null |
45+
Where-Object { $_ -match '^\.serena/memories/.*\.md$' -and $_ -notmatch 'skills-.*-index\.md$' }
46+
47+
if (-not $stagedFiles) {
48+
Write-Host "No skill files staged. Skipping format validation." -ForegroundColor Gray
49+
exit 0
50+
}
51+
52+
$filesToCheck = $stagedFiles | ForEach-Object { Get-Item $_ -ErrorAction SilentlyContinue }
53+
} else {
54+
# Check all skill files (exclude index files)
55+
$filesToCheck = Get-ChildItem -Path $Path -Filter "*.md" -ErrorAction SilentlyContinue |
56+
Where-Object { $_.Name -notmatch '^skills-.*-index\.md$' -and $_.Name -ne 'memory-index.md' }
57+
}
58+
59+
if (-not $filesToCheck) {
60+
Write-Host "No skill files found to validate." -ForegroundColor Gray
61+
exit 0
62+
}
63+
64+
Write-Host "Validating skill format (ADR-017: one skill per file)..." -ForegroundColor Cyan
65+
66+
foreach ($file in $filesToCheck) {
67+
$content = Get-Content $file.FullName -Raw -ErrorAction SilentlyContinue
68+
if (-not $content) { continue }
69+
70+
# Count skill headers (## Skill-*-NNN:)
71+
$skillHeaders = [regex]::Matches($content, '(?m)^## Skill-[A-Za-z]+-[0-9]+:')
72+
73+
if ($skillHeaders.Count -gt 1) {
74+
# Bundled format detected
75+
Write-Host " BUNDLED: $($file.Name) contains $($skillHeaders.Count) skills" -ForegroundColor Yellow
76+
$script:BundledFiles += @{
77+
File = $file.Name
78+
Count = $skillHeaders.Count
79+
}
80+
$script:ExitCode = 1
81+
}
82+
}
83+
84+
# Summary
85+
Write-Host ""
86+
if ($script:BundledFiles.Count -gt 0) {
87+
Write-Host "=== Bundled Format Detected ===" -ForegroundColor Yellow
88+
Write-Host "The following files contain multiple skills:" -ForegroundColor Yellow
89+
$script:BundledFiles | ForEach-Object {
90+
Write-Host " - $($_.File): $($_.Count) skills" -ForegroundColor Yellow
91+
}
92+
Write-Host ""
93+
Write-Host "ADR-017 requires ONE skill per file. No exceptions." -ForegroundColor Red
94+
Write-Host "Split bundled skills into separate atomic files." -ForegroundColor Red
95+
Write-Host ""
96+
97+
if ($CI) {
98+
Write-Host "Result: FAILED" -ForegroundColor Red
99+
exit 1
100+
} else {
101+
Write-Host "Result: WARNING (non-blocking for legacy files)" -ForegroundColor Yellow
102+
exit 0
103+
}
104+
} else {
105+
Write-Host "Result: PASSED - All skill files are atomic format" -ForegroundColor Green
106+
exit 0
107+
}

src/claude/skillbook.md

Lines changed: 10 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,11 @@ Correct format (maximum token efficiency):
169169
| `skills-{domain}-index.md` | L2 routing table | `skills-pr-review-index.md` |
170170
| `{domain}-{topic}.md` | L3 atomic content | `pr-review-security.md` |
171171

172-
## Skill File Formats (ADR-017)
172+
## Skill File Format (ADR-017)
173173

174-
Skills are stored as markdown files in `.serena/memories/`. Two canonical formats exist:
174+
**ONE format. ALWAYS consistent. No exceptions.**
175175

176-
### Format A: Standalone Skill (Major Skills)
177-
178-
Use for skills that are referenced independently or represent major capabilities.
176+
Skills are stored as atomic markdown files in `.serena/memories/`. Every skill uses this format:
179177

180178
```markdown
181179
# Skill-{Category}-{NNN}: {Title}
@@ -194,14 +192,11 @@ Use for skills that are referenced independently or represent major capabilities
194192

195193
## Anti-Pattern
196194

197-
{What NOT to do}
198-
199-
## Related
200-
201-
- **BLOCKS**: {Skills this blocks}
202-
- **ENABLES**: {Skills this enables}
195+
{What NOT to do - optional, include only if there's a common mistake}
203196
```
204197

198+
**One skill per file.** No bundling. No decision trees. No exceptions.
199+
205200
**Example** (from `session-init-serena.md`):
206201

207202
```markdown
@@ -221,102 +216,11 @@ Use for skills that are referenced independently or represent major capabilities
221216
3. Proceed with work
222217
```
223218

224-
### Format B: Bundled Skills (Related Workflows)
225-
226-
Use for multiple related skills that share a workflow context.
227-
228-
```markdown
229-
# {Domain}: {Topic Title}
230-
231-
## Skill-{Category}-{NNN}: {First Skill Title}
232-
233-
**Statement**: {Atomic strategy}
234-
235-
**Atomicity**: {%} | **Impact**: {1-10}
236-
237-
{Code example}
238-
239-
## Skill-{Category}-{NNN}: {Second Skill Title}
240-
241-
**Statement**: {Atomic strategy}
242-
243-
**Atomicity**: {%} | **Impact**: {1-10}
244-
245-
{Code example}
246-
```
247-
248-
**Example** (from `pr-review-acknowledgment.md`):
249-
250-
```markdown
251-
# PR Review: Acknowledgment Protocol
252-
253-
## Skill-PR-Comment-001: Acknowledgment BLOCKING Gate
254-
255-
**Statement**: Phase 3 BLOCKED until eyes count equals comment count.
256-
257-
**Atomicity**: 100% | **Tag**: critical
258-
259-
## Skill-PR-Comment-002: Session-Specific Work Tracking
260-
261-
**Statement**: Track 'NEW this session' separately from 'DONE prior'.
262-
263-
**Atomicity**: 100% | **Tag**: critical
264-
```
265-
266-
### Format Selection Decision Tree
267-
268-
```mermaid
269-
flowchart TD
270-
START([New Skill]) --> Q1{CRITICAL/BLOCKING?<br/>See criteria below}
271-
Q1 -->|YES| A1[Format A<br/>Standalone]
272-
Q1 -->|NO| Q2{2+ related skills<br/>same workflow?}
273-
Q2 -->|YES| B1[Format B<br/>Bundled]
274-
Q2 -->|NO| Q3{Has BLOCKS/ENABLES<br/>relationships?}
275-
Q3 -->|YES| A2[Format A<br/>Standalone]
276-
Q3 -->|NO| EITHER[Either Format<br/>Acceptable]
277-
278-
A1 --> DONE([Create File])
279-
A2 --> DONE
280-
B1 --> DONE
281-
EITHER --> DONE
282-
```
283-
284-
**CRITICAL/BLOCKING Definition** (any one triggers Format A):
285-
286-
- Impact score >= 9
287-
- Blocks a protocol gate (SESSION-PROTOCOL.md)
288-
- Tagged with `#P0` or `#BLOCKING`
289-
- Referenced in `.agents/SESSION-PROTOCOL.md`
290-
291-
**"Has BLOCKS/ENABLES relationships"**: Skill will be cited in other skills' Related sections.
292-
293-
### Index Selection Decision Tree
294-
295-
```mermaid
296-
flowchart TD
297-
START([New Skill]) --> Q1{Skill topic matches<br/>existing domain index?}
298-
Q1 -->|YES| ADD[Add to existing<br/>skills-DOMAIN-index.md]
299-
Q1 -->|NO| Q2{5+ skills expected<br/>in this topic area?}
300-
Q2 -->|YES| CREATE[Create new<br/>skills-DOMAIN-index.md]
301-
Q2 -->|NO| Q3{Closest related<br/>domain?}
302-
Q3 --> RELATED[Add to related<br/>domain index]
303-
304-
ADD --> UPDATE[Update memory-index.md<br/>if new keywords]
305-
CREATE --> UPDATE
306-
RELATED --> UPDATE
307-
```
308-
309-
**Index Selection Rules:**
310-
311-
1. **Match existing domain**: Check `memory-index.md` keywords. If skill keywords overlap >50% with existing domain, add there.
312-
2. **Create new domain**: Only if 5+ skills expected AND no existing domain covers topic.
313-
3. **Fallback to related**: If <5 skills expected, add to closest related domain.
314-
315-
**Example decisions:**
219+
### Index Selection
316220

317-
- Skill about PR security → `skills-pr-review-index.md` (PR workflow context)
318-
- Skill about skill formatting → `skills-documentation-index.md` (documentation context)
319-
- Skill about Pester mocking → `skills-pester-testing-index.md` (testing context)
221+
1. Check `memory-index.md` for matching domain keywords
222+
2. Add skill to existing domain index if keywords overlap >50%
223+
3. Create new domain index only if 5+ skills exist AND no domain covers topic
320224

321225
### Activation Vocabulary Rules
322226

0 commit comments

Comments
 (0)