refactor(plugin)!: ship as a Claude Code plugin, one dir link per harness

Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so
it is now a marketplace hosting exactly one plugin whose root is the repo
root (source: "."). Claude Code installs it from git; no symlinks involved.

Why: install.sh wired the library into every consuming repo as an ABSOLUTE
symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when
local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated
the links — 243 dangling links across 12 repos, hidden from git by the
**/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots
(/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an
absolute link stored there is broken on one side by construction. Re-running
the installer cannot fix that; only removing the mechanism can.

install.sh keeps the harnesses with no plugin system and drops from 42 links
per harness to one directory link, via the convergent ~/.agents/skills
convention that Pi and OpenCode both read:

  ~/.agents/skills          -> $CHECKOUT_DIR/skills
  ~/.config/crush/skills    -> ~/.agents/skills
  ~/.config/opencode/skills -> ~/.agents/skills

wire_claude_repo is deleted outright rather than gated behind a flag — on a
mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go
too; both unused. CHECKOUT_DIR keeps its host-local default deliberately:
pointing it into ~/dev would put a git working tree inside iCloud with two
concurrent writers.

Taskfile drops five near-identical wiring loops (they had already drifted)
and delegates to install.sh. `task check` gains frontmatter validation, a
stray-root-entry gate, and manifest/tag version parity — the loose
secret-hygiene.md sat unloadable for months because nothing checked layout.

Verified: claude plugin validate . passes clean; a probe skill loaded as
skills:zzprobe through --plugin-dir; task check green at 42 skills.

Refs: #23
Bump-Type: minor

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
This commit is contained in:
2026-08-23 14:29:51 +02:00
co-authored by Claude Opus 5
parent 21be3ea245
commit 56a947b2a0
88 changed files with 182 additions and 253 deletions
+286
View File
@@ -0,0 +1,286 @@
# Managing Complexity
## The Two Types of Complexity
### Essential Complexity
Inherent to the problem domain. Cannot be removed, only managed.
- Business rules
- Domain logic
- User requirements
### Accidental Complexity
Introduced by our solutions. CAN and SHOULD be minimized.
- Poor abstractions
- Unnecessary indirection
- Framework ceremony
- Technical debt
**Goal: Minimize accidental complexity while clearly expressing essential complexity.**
---
## Detecting Complexity
### 1. Change Amplification
Small changes require touching many files.
**Symptom:** "To add this field, I need to update 15 files."
**Cause:** Scattered responsibilities, poor abstraction boundaries.
### 2. Cognitive Load
Code is hard to understand, requires holding too much in memory.
**Symptom:** "I need to understand 10 other classes to understand this one."
**Cause:** Tight coupling, hidden dependencies, unclear naming.
### 3. Unknown Unknowns
Behavior is surprising, side effects are hidden.
**Symptom:** "I changed this, and something completely unrelated broke."
**Cause:** Global state, hidden dependencies, implicit contracts.
---
## The XP Values for Fighting Complexity
From Extreme Programming:
### 1. Communication
Code should communicate clearly. Names, structure, tests all contribute.
### 2. Simplicity
Do the simplest thing that could possibly work.
### 3. Feedback
Fast feedback loops catch complexity early. TDD, CI, code review.
### 4. Courage
Refactor aggressively. Don't let complexity accumulate.
### 5. Respect
Respect future readers (including yourself). Write for humans first.
---
## KISS - Keep It Simple, Silly
> "The simplest solution that works is usually the best."
### How to Apply:
1. Start with the obvious solution
2. Only add complexity when REQUIRED
3. Prefer boring, well-understood approaches
4. Question every abstraction
```typescript
// Over-engineered
class UserServiceFactoryProvider {
private static instance: UserServiceFactoryProvider;
static getInstance(): UserServiceFactoryProvider { ... }
createFactory(): UserServiceFactory { ... }
}
// KISS
class UserService {
getUser(id: string): User { ... }
}
```
---
## YAGNI - You Aren't Gonna Need It
> "Don't build features until they're actually needed."
### Warning Signs:
- "We might need this later"
- "It would be nice to have"
- "Just in case"
- "For future extensibility"
### The Cost of YAGNI Violations:
1. **Development time** - Building unused features
2. **Maintenance burden** - Code that must be maintained
3. **Cognitive load** - More to understand
4. **Wrong abstraction** - Guessing future needs incorrectly
```typescript
// YAGNI violation: Building for hypothetical needs
class User {
// "We might need these someday"
middleName?: string;
secondaryEmail?: string;
faxNumber?: string;
linkedinProfile?: string;
twitterHandle?: string;
}
// YAGNI: Only what's needed NOW
class User {
name: string;
email: Email;
}
```
---
## DRY - Don't Repeat Yourself (with The Rule of Three)
> "Every piece of knowledge should have a single, unambiguous representation."
### BUT: The Rule of Three
**Don't extract duplication until you see it THREE times.**
Why? The wrong abstraction is worse than duplication.
```
Duplication #1 → Leave it
Duplication #2 → Note it, leave it
Duplication #3 → NOW extract it
```
### Example:
```typescript
// First time - leave it
function processUserOrder(order) {
validate(order);
calculateTax(order);
save(order);
}
// Second time - note the similarity, but leave it
function processGuestOrder(order) {
validate(order);
calculateTax(order);
save(order);
sendGuestEmail(order);
}
// Third time - NOW extract
function processCorporateOrder(order) {
validate(order);
calculateTax(order);
save(order);
applyCorporateDiscount(order);
}
// After three, extract the common parts
function processOrder(order: Order, postProcessing: (o: Order) => void) {
validate(order);
calculateTax(order);
save(order);
postProcessing(order);
}
```
---
## Separation of Concerns
> "Each module should address a single concern."
### Concerns to Separate:
- **Business logic** vs **Infrastructure**
- **What** (policy) vs **How** (mechanism)
- **Input** vs **Processing** vs **Output**
- **Data** vs **Behavior**
### Example:
```typescript
// BAD: Mixed concerns
class OrderProcessor {
process(order: Order) {
// Validation
if (!order.items.length) throw new Error('Empty');
// Business logic
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
// Persistence
const db = new Database();
db.query(`INSERT INTO orders...`);
// Notification
const email = new EmailClient();
email.send(order.customer.email, 'Order confirmed');
}
}
// GOOD: Separated concerns
class OrderProcessor {
constructor(
private validator: OrderValidator,
private calculator: OrderCalculator,
private repository: OrderRepository,
private notifier: OrderNotifier
) {}
process(order: Order): ProcessResult {
this.validator.validate(order);
const total = this.calculator.calculateTotal(order);
const savedOrder = this.repository.save(order);
this.notifier.notifyConfirmation(savedOrder);
return ProcessResult.success(savedOrder);
}
}
```
---
## Managing Technical Debt
### Types of Technical Debt:
1. **Deliberate** - Conscious trade-off for speed
2. **Accidental** - Mistakes, lack of knowledge
3. **Bit rot** - Code degrades over time
### The Boy Scout Rule:
> "Leave the code better than you found it."
Every time you touch code:
- Improve one small thing
- Fix one naming issue
- Extract one method
- Add one missing test
### When to Pay Down Debt:
- When it's in your path (you're already there)
- When it's blocking new features
- When it's causing bugs
- During dedicated refactoring time
### When NOT to Refactor:
- Code that works and won't change
- Code being replaced soon
- When you don't have tests
---
## The Four Elements of Simple Design
In priority order (from XP):
1. **Runs all the tests**
- If it doesn't work, nothing else matters
2. **Expresses intent**
- Clear names, obvious structure
- Code tells the story
3. **No duplication**
- DRY (but Rule of Three)
- Single source of truth
4. **Minimal**
- Fewest classes and methods possible
- Remove anything unnecessary
If these four are true, the design is simple enough.