Add cross-tool positioning, Python helpers, tiers, and hygiene docs

Five improvements to position the library as a serious engineering project:

1. Cross-tool compatibility — new README "Works With" section honestly
   documenting where skills run (Claude Code natively; SKILL.md bodies
   port to other agents and chat LLMs as system prompts).

2. Python helper scripts (stdlib-only) for the three strongest skills:
   - sprint-planning: capacity_calculator.py (recommended commitment)
   - rice-prioritisation: rice_calculator.py (ranks, flags quick wins/moonshots)
   - cs-health-scorecard: health_score.py (weighted total + RAG)
   Each is wired into its SKILL.md and synced to the plugin copies.

3. Explicit skill tiering — TIERS.md + README section marking 46
   Production-Ready skills and calling out Experimental (external-dependency)
   ones; everything else is Stable.

4. Repository hygiene — new CHANGELOG.md (Keep a Changelog format) and
   SKILL-AUTHORING-STANDARD.md; refreshed SECURITY.md version table and
   helper-script disclosure; added .gitignore.

5. Related Projects — README section linking to alirezarezvani/claude-skills
   and the major awesome-claude-skills / awesome-claude-code lists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016JWn5jRD5tcEFKrubjQ6Px
This commit is contained in:
Claude
2026-06-17 07:48:48 +00:00
parent 2299e59d72
commit 760f979365
20 changed files with 1514 additions and 5 deletions
@@ -25,6 +25,24 @@ Ask the user for these if not provided:
## RICE Formula
RICE Score = (Reach × Impact × Confidence) / Effort
## Programmatic Helper
This skill ships with a stdlib-only Python script that calculates and ranks RICE scores so the maths is consistent and the quick-win / moonshot flags are applied by rule, not by feel. Feed it the initiatives once R, I, C, and E are gathered.
```bash
# From a JSON file (confidence accepts 0.8 or 80)
python3 scripts/rice_calculator.py initiatives.json
# Or from a CSV with header: name,reach,impact,confidence,effort
python3 scripts/rice_calculator.py initiatives.csv --format csv
# Or piped in
echo '[{"name":"Onboarding","reach":5000,"impact":2,"confidence":0.8,"effort":3}]' \
| python3 scripts/rice_calculator.py -
```
It outputs a ranked table with computed RICE scores and auto-flags **quick-win** (strong score, low relative effort), **moonshot** (high impact, high effort), and **low-confidence** (≤50%) items. Use the computed ranking as the starting point, then apply the validation step below — never accept a surprising top rank without checking the estimates behind it.
## Process
1. For each initiative provided, gather or estimate R, I, C, E values
2. Flag where estimates are weak and note what data would improve them
@@ -0,0 +1,170 @@
#!/usr/bin/env python3
"""RICE score calculator for the rice-prioritisation skill.
Computes RICE = (Reach × Impact × Confidence) / Effort for a list of
initiatives, ranks them, and flags quick wins and moonshots so the ranking in a
prioritisation doc is calculated consistently rather than eyeballed. Pure Python
standard library — no dependencies, no network access.
Input
-----
A JSON or CSV list of initiatives. Each needs: name, reach, impact, confidence,
effort.
- impact uses the standard RICE scale (3, 2, 1, 0.5, 0.25) but any number works.
- confidence is a fraction (0.8) or a percentage (80) — both are accepted.
- effort is in person-months and must be > 0.
JSON example (rice.json):
[
{"name": "Onboarding redesign", "reach": 5000, "impact": 2, "confidence": 0.8, "effort": 3},
{"name": "Dark mode", "reach": 8000, "impact": 0.5, "confidence": 1.0, "effort": 1}
]
CSV example (header row required):
name,reach,impact,confidence,effort
Onboarding redesign,5000,2,0.8,3
Dark mode,8000,0.5,1.0,1
Usage
-----
python3 rice_calculator.py rice.json
python3 rice_calculator.py rice.csv --format csv
cat rice.json | python3 rice_calculator.py - --json
"""
from __future__ import annotations
import argparse
import csv
import io
import json
import sys
from dataclasses import dataclass
@dataclass
class Initiative:
name: str
reach: float
impact: float
confidence: float
effort: float
@property
def score(self) -> float:
if self.effort <= 0:
raise ValueError(f"Effort for '{self.name}' must be greater than 0.")
return (self.reach * self.impact * self.confidence) / self.effort
def _normalise_confidence(value: float) -> float:
"""Accept 80 or 0.8; return a fraction between 0 and 1."""
return value / 100.0 if value > 1 else value
def _to_initiative(row: dict) -> Initiative:
try:
return Initiative(
name=str(row["name"]).strip(),
reach=float(row["reach"]),
impact=float(row["impact"]),
confidence=_normalise_confidence(float(row["confidence"])),
effort=float(row["effort"]),
)
except KeyError as exc:
raise ValueError(f"Missing required field {exc} in row: {row}") from None
def load(text: str, fmt: str) -> list[Initiative]:
if fmt == "csv":
rows = list(csv.DictReader(io.StringIO(text)))
else:
rows = json.loads(text)
if not isinstance(rows, list):
raise ValueError("Input must be a list of initiatives.")
return [_to_initiative(r) for r in rows]
def rank(initiatives: list[Initiative]) -> list[dict]:
scored = []
for i in initiatives:
scored.append({
"name": i.name,
"reach": i.reach,
"impact": i.impact,
"confidence": round(i.confidence, 2),
"effort": i.effort,
"rice_score": round(i.score, 1),
})
scored.sort(key=lambda d: d["rice_score"], reverse=True)
if scored:
max_score = max(d["rice_score"] for d in scored) or 1
max_effort = max(d["effort"] for d in scored) or 1
for rank_index, d in enumerate(scored, start=1):
d["rank"] = rank_index
flags = []
# Quick win: strong score relative to the field, low relative effort.
if d["rice_score"] >= 0.5 * max_score and d["effort"] <= 0.33 * max_effort:
flags.append("quick-win")
# Moonshot: high raw impact, high relative effort.
if d["impact"] >= 2 and d["effort"] >= 0.66 * max_effort:
flags.append("moonshot")
# Low-confidence estimates should be revisited before acting.
if d["confidence"] <= 0.5:
flags.append("low-confidence")
d["flags"] = flags
return scored
def _render(scored: list[dict]) -> str:
header = f"{'#':>2} {'Initiative':<32} {'Reach':>8} {'Imp':>4} {'Conf':>5} {'Eff':>5} {'RICE':>8} Flags"
lines = ["RICE Prioritisation", "=" * len(header), header, "-" * len(header)]
for d in scored:
lines.append(
f"{d['rank']:>2} {d['name'][:32]:<32} {d['reach']:>8g} {d['impact']:>4g} "
f"{d['confidence']:>5.2f} {d['effort']:>5g} {d['rice_score']:>8g} {', '.join(d['flags'])}"
)
quick = [d["name"] for d in scored if "quick-win" in d["flags"]]
moon = [d["name"] for d in scored if "moonshot" in d["flags"]]
lowc = [d["name"] for d in scored if "low-confidence" in d["flags"]]
lines.append("")
lines.append(f"Quick wins (do alongside bigger bets): {', '.join(quick) or 'none'}")
lines.append(f"Moonshots (high impact, high effort): {', '.join(moon) or 'none'}")
lines.append(f"Low confidence — revisit estimates: {', '.join(lowc) or 'none'}")
return "\n".join(lines)
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("input", help="Path to a JSON/CSV file of initiatives, or '-' for stdin.")
parser.add_argument("--format", choices=["json", "csv"], help="Input format (inferred from extension if omitted).")
parser.add_argument("--json", action="store_true", dest="as_json", help="Emit ranked JSON instead of a table.")
args = parser.parse_args(argv)
text = sys.stdin.read() if args.input == "-" else None
fmt = args.format
if text is None:
try:
text = open(args.input).read()
except OSError as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
if fmt is None:
fmt = "csv" if args.input.lower().endswith(".csv") else "json"
fmt = fmt or "json"
try:
scored = rank(load(text, fmt))
except (ValueError, json.JSONDecodeError) as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
print(json.dumps(scored, indent=2) if args.as_json else _render(scored))
return 0
if __name__ == "__main__":
raise SystemExit(main())