@mmerterden/multi-agent-pipeline 20.5.0 → 20.7.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 +36 -0
- package/LICENSE +10 -0
- package/docs/facts.json +5 -4
- package/install/_dev-only-files.mjs +1 -0
- package/manifest.json +84 -82
- package/package.json +4 -3
- package/pipeline/lib/confusables.json +100 -0
- package/pipeline/lib/normalize-text.mjs +48 -0
- package/pipeline/lib/outbound-gate.mjs +10 -1
- package/pipeline/lib/redact.mjs +4 -1
- package/pipeline/lib/vercel-deploy.sh +5 -7
- package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
- package/pipeline/scripts/_notices.mjs +11 -0
- package/pipeline/scripts/agent-guard.py +30 -1
- package/pipeline/scripts/gen-skills-index.mjs +1 -1
- package/pipeline/scripts/pre-commit-check.sh +59 -16
- package/pipeline/scripts/pre-push-check.sh +3 -3
- package/pipeline/scripts/run-ui-tests.sh +5 -5
- package/pipeline/scripts/website-deploy-commit.sh +3 -2
- package/pipeline/skills/.skill-manifest.json +39 -39
- package/pipeline/skills/shared/README.md +1 -1
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
- package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/council/SKILL.md +1 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
- package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
- package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
- package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
- package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
- package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
- package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
- package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
- package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
- package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
- package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
- package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Fidelity
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
publish reflects the code, not a guess. Read-only.
|
|
8
|
-
|
|
9
|
-
Checks (each reported, never auto-fixed):
|
|
10
|
-
1. newKey ∈ screen code - every row's `newKey` should appear as a wired
|
|
11
|
-
`LocalizationStringKey.<...>` call site (or `"Key".localized`, or a web
|
|
12
|
-
`t('Key')` / `$t('Key')` i18n call) in --screen-path.
|
|
13
|
-
Component-owned keys (`(owned by ...)` / `(DS bileşen...)`) are exempt (they live in the
|
|
14
|
-
component, not the screen file) and listed separately.
|
|
15
|
-
2. code keys ∉ map - `LocalizationStringKey.<...>` wired in the screen but with no
|
|
16
|
-
row → missing coverage (add a row or confirm it's out of scope).
|
|
17
|
-
3. value gaps - `new.tr` empty (verdict≠new), or legacy entirely empty where
|
|
18
|
-
the verdict claims reuse/review.
|
|
19
|
-
4. untranslated - a row whose `new.tr` == `new.en` (flag, as the renderer does).
|
|
20
|
-
5. resources (optional) - with --resources-root, the new key's Suggested/<Key>.json exists.
|
|
21
|
-
|
|
22
|
-
Exit code 2 when any hard fidelity issue is found (unverified non-component key, code key
|
|
23
|
-
missing from the map, or a reuse/review row with no legacy value), so it can gate a run.
|
|
2
|
+
"""Fidelity gate: reconcile a reuse-map mapping against the implemented screen.
|
|
3
|
+
|
|
4
|
+
Checks that every mapped newKey is wired in the screen code, that every key
|
|
5
|
+
the code wires is mapped, and that no row carries an empty or invented value.
|
|
6
|
+
Exit 2 when a hard issue is found (blocks publishing), 0 otherwise.
|
|
24
7
|
"""
|
|
25
8
|
import argparse
|
|
26
9
|
import json
|
|
@@ -28,145 +11,178 @@ import os
|
|
|
28
11
|
import re
|
|
29
12
|
import sys
|
|
30
13
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
RE_LITERAL = re.compile(r'"([A-Za-z0-9_.]+)"\s*\.\s*localized')
|
|
34
|
-
# Web (react-i18next / next-intl `t('key')`; vue-i18n `$t('key')`)
|
|
35
|
-
RE_WEB_T = re.compile(r"(?<!\$)\bt\(\s*['\"]([A-Za-z0-9_.\-]+)['\"]")
|
|
36
|
-
RE_WEB_VUE_T = re.compile(r"\$t\(\s*['\"]([A-Za-z0-9_.\-]+)['\"]")
|
|
37
|
-
# RE_LSK is greedy across dots, so `...StringKey.Ns.leaf.localized` captures the accessor
|
|
38
|
-
# too. Strip it, or no call site ever matches its mapping row and every wired key is
|
|
39
|
-
# reported unmapped.
|
|
40
|
-
RE_ACCESSOR = re.compile(r"\.localized\w*$")
|
|
41
|
-
MARKER = re.compile(r"\(.*(owned by|bileşen|component).*\)", re.I)
|
|
14
|
+
EXTENSIONS = {".swift", ".kt", ".kts", ".xml", ".ts", ".tsx", ".js", ".jsx", ".vue"}
|
|
15
|
+
SKIP_PARTS = ("/.git", "/Generated/")
|
|
42
16
|
|
|
17
|
+
WORD = "A-Za-z0-9_"
|
|
18
|
+
LSK = re.compile(rf"LocalizationStringKey((?:\.[A-Za-z_][{WORD}]*)+)")
|
|
19
|
+
LITERAL_LOCALIZED = re.compile(rf"\"([{WORD}.]+)\"\.localized\b")
|
|
20
|
+
WEB_T = re.compile(r"(?<![\w$])t\(\s*(['\"])([A-Za-z0-9_.\-]+)\1")
|
|
21
|
+
WEB_DOLLAR_T = re.compile(r"\$t\(\s*(['\"])([A-Za-z0-9_.\-]+)\1")
|
|
22
|
+
TRAILING_MARKER = re.compile(r"\s*\([^()]*\)\s*$")
|
|
23
|
+
COMPONENT_MARKER = re.compile(r"\([^)]*(owned by|bile\u015fen|component)[^)]*\)", re.IGNORECASE)
|
|
24
|
+
PLACEHOLDER = re.compile(r"<[^<>]+>")
|
|
43
25
|
|
|
44
|
-
def clean_key(k):
|
|
45
|
-
"""Strip a trailing '(owned by ...)' / '(DS bileşene ait)' marker → bare dotted key."""
|
|
46
|
-
return re.sub(r"\s*\(.*\)\s*$", "", (k or "")).strip()
|
|
47
26
|
|
|
27
|
+
def strip_accessor(chain):
|
|
28
|
+
segments = chain.strip(".").split(".")
|
|
29
|
+
while segments and segments[-1].startswith("localized"):
|
|
30
|
+
segments.pop()
|
|
31
|
+
return ".".join(segments)
|
|
48
32
|
|
|
49
|
-
def is_component(k):
|
|
50
|
-
return bool(MARKER.search(k or ""))
|
|
51
33
|
|
|
34
|
+
def normalize_key(key):
|
|
35
|
+
return ".".join(seg[:1].upper() + seg[1:] for seg in key.split("."))
|
|
52
36
|
|
|
53
|
-
def norm_key(k):
|
|
54
|
-
return clean_key(k).lower()
|
|
55
37
|
|
|
38
|
+
def source_files(root):
|
|
39
|
+
if os.path.isfile(root):
|
|
40
|
+
yield root
|
|
41
|
+
return
|
|
42
|
+
for current, dirs, files in os.walk(root):
|
|
43
|
+
probe = current.replace(os.sep, "/") + "/"
|
|
44
|
+
if any(part in probe for part in SKIP_PARTS):
|
|
45
|
+
dirs[:] = []
|
|
46
|
+
continue
|
|
47
|
+
for name in sorted(files):
|
|
48
|
+
if os.path.splitext(name)[1] in EXTENSIONS:
|
|
49
|
+
yield os.path.join(current, name)
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
keys
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
else:
|
|
64
|
-
for dp, _d, names in os.walk(screen_path):
|
|
65
|
-
if "/.git" in dp:
|
|
66
|
-
continue
|
|
67
|
-
files += [os.path.join(dp, n) for n in names if n.endswith(EXTS)]
|
|
68
|
-
for f in files:
|
|
51
|
+
|
|
52
|
+
def scan_code(root):
|
|
53
|
+
keys = set()
|
|
54
|
+
corpus = []
|
|
55
|
+
scanned = 0
|
|
56
|
+
for path in source_files(root):
|
|
69
57
|
try:
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
with open(path, encoding="utf-8") as stream:
|
|
59
|
+
text = stream.read()
|
|
60
|
+
except (OSError, UnicodeDecodeError):
|
|
72
61
|
continue
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
62
|
+
scanned += 1
|
|
63
|
+
corpus.append(text.lower())
|
|
64
|
+
chains = (strip_accessor(hit.group(1)) for hit in LSK.finditer(text))
|
|
65
|
+
keys.update(chain.lower() for chain in chains if chain)
|
|
66
|
+
for pattern, group in ((LITERAL_LOCALIZED, 1), (WEB_T, 2), (WEB_DOLLAR_T, 2)):
|
|
67
|
+
keys.update(hit.group(group).lower() for hit in pattern.finditer(text))
|
|
68
|
+
return keys, "\n".join(corpus), scanned
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def is_component(row):
|
|
72
|
+
text = " ".join(str(row.get(f) or "") for f in ("newKey", "element", "note"))
|
|
73
|
+
return bool(COMPONENT_MARKER.search(text))
|
|
83
74
|
|
|
84
75
|
|
|
85
|
-
def
|
|
86
|
-
""
|
|
87
|
-
|
|
88
|
-
return
|
|
76
|
+
def is_dynamic(row, key):
|
|
77
|
+
element = str(row.get("element") or "").lower()
|
|
78
|
+
note = str(row.get("note") or "").lower()
|
|
79
|
+
return (
|
|
80
|
+
key.startswith("(dynamic")
|
|
81
|
+
or bool(PLACEHOLDER.search(key))
|
|
82
|
+
or "dinamik" in element
|
|
83
|
+
or "dynamic" in element
|
|
84
|
+
or "enumerate at runtime" in note
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def suggested_exists(root, key):
|
|
89
|
+
name = normalize_key(key) + ".json"
|
|
90
|
+
candidates = [
|
|
91
|
+
os.path.join(root, "Localization", "Suggested", name),
|
|
92
|
+
os.path.join(root, "Resources", "Localization", "LocalizationStrings", "Sources", "Suggested", name),
|
|
93
|
+
]
|
|
94
|
+
return any(os.path.isfile(p) for p in candidates)
|
|
89
95
|
|
|
90
96
|
|
|
91
97
|
def main():
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
rows =
|
|
102
|
-
code_keys, corpus,
|
|
103
|
-
|
|
104
|
-
verified
|
|
105
|
-
|
|
98
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
99
|
+
parser.add_argument("--mapping", required=True, help="the reuse-map JSON")
|
|
100
|
+
parser.add_argument("--screen-path", required=True, help="folder or single file of the built screen")
|
|
101
|
+
parser.add_argument("--resources-root", help="resources checkout or snapshot; turns on the Suggested-file check")
|
|
102
|
+
parser.add_argument("--out", help="JSON report destination; stdout when omitted")
|
|
103
|
+
args = parser.parse_args()
|
|
104
|
+
|
|
105
|
+
with open(args.mapping, encoding="utf-8") as stream:
|
|
106
|
+
mapping = json.load(stream)
|
|
107
|
+
rows = mapping.get("rows") or []
|
|
108
|
+
code_keys, corpus, scanned = scan_code(args.screen_path)
|
|
109
|
+
|
|
110
|
+
verified = 0
|
|
111
|
+
exempt = 0
|
|
112
|
+
weak, unverified = [], []
|
|
113
|
+
gaps, untranslated = [], []
|
|
106
114
|
map_keys = set()
|
|
107
115
|
|
|
108
|
-
for
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
for row in rows:
|
|
117
|
+
raw_key = str(row.get("newKey") or "").strip()
|
|
118
|
+
key = raw_key if raw_key.startswith("(dynamic") else TRAILING_MARKER.sub("", raw_key)
|
|
119
|
+
component = is_component(row)
|
|
120
|
+
dynamic = is_dynamic(row, key)
|
|
121
|
+
if key:
|
|
122
|
+
map_keys.add(key.lower())
|
|
123
|
+
|
|
124
|
+
if component or dynamic:
|
|
125
|
+
exempt += 1
|
|
126
|
+
elif key.lower() in code_keys:
|
|
127
|
+
verified += 1
|
|
119
128
|
else:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
code_not_mapped = sorted(k for k in code_keys if k not in map_keys)
|
|
141
|
-
|
|
129
|
+
leaf = key.rsplit(".", 1)[-1].lower()
|
|
130
|
+
whole_word = r"\b%s\b" % re.escape(leaf)
|
|
131
|
+
if leaf and re.search(whole_word, corpus):
|
|
132
|
+
weak.append(key)
|
|
133
|
+
else:
|
|
134
|
+
unverified.append({"key": key, "element": row.get("element")})
|
|
135
|
+
|
|
136
|
+
verdict = row.get("verdict")
|
|
137
|
+
new = row.get("new") or {}
|
|
138
|
+
legacy = row.get("legacy") or {}
|
|
139
|
+
if verdict != "new" and not new.get("tr") and not dynamic:
|
|
140
|
+
gaps.append({"key": key, "issue": "new.tr empty"})
|
|
141
|
+
if verdict in ("reuse", "review") and not (legacy.get("en") or legacy.get("tr")):
|
|
142
|
+
gaps.append({"key": key, "issue": f"verdict={verdict} but no legacy value"})
|
|
143
|
+
if new.get("tr") and new.get("tr") == new.get("en"):
|
|
144
|
+
untranslated.append(key)
|
|
145
|
+
if args.resources_root and not component and not dynamic and key and not suggested_exists(args.resources_root, key):
|
|
146
|
+
gaps.append({"key": key, "issue": f"no Suggested/{normalize_key(key)}.json"})
|
|
147
|
+
|
|
148
|
+
not_in_map = sorted(code_keys - map_keys)
|
|
142
149
|
report = {
|
|
143
|
-
"screen":
|
|
144
|
-
"
|
|
145
|
-
|
|
146
|
-
"
|
|
147
|
-
|
|
150
|
+
"screen": mapping.get("screen"),
|
|
151
|
+
"rows": len(rows),
|
|
152
|
+
"filesScanned": scanned,
|
|
153
|
+
"newKeyInCode": {
|
|
154
|
+
"verified": verified,
|
|
155
|
+
"weak": weak,
|
|
156
|
+
"unverified": unverified,
|
|
157
|
+
"component_or_dynamic": exempt,
|
|
158
|
+
},
|
|
159
|
+
"codeKeysNotInMap": not_in_map,
|
|
160
|
+
"valueGaps": gaps,
|
|
161
|
+
"untranslated": untranslated,
|
|
148
162
|
}
|
|
149
|
-
|
|
150
|
-
|
|
163
|
+
text = json.dumps(report, indent=2, ensure_ascii=False) + "\n"
|
|
151
164
|
if args.out:
|
|
152
|
-
with open(args.out, "w", encoding="utf-8") as
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
f"#
|
|
161
|
-
f"
|
|
162
|
-
|
|
163
|
-
sys.stderr
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
with open(args.out, "w", encoding="utf-8") as sink:
|
|
166
|
+
sink.write(text)
|
|
167
|
+
else:
|
|
168
|
+
sys.stdout.write(text)
|
|
169
|
+
|
|
170
|
+
no_legacy = [g for g in gaps if "no legacy value" in g["issue"]]
|
|
171
|
+
hard = len(unverified) + len(not_in_map) + len(no_legacy)
|
|
172
|
+
print(
|
|
173
|
+
f"# rows {len(rows)}, files {scanned}: verified {verified}, weak {len(weak)}, "
|
|
174
|
+
f"UNVERIFIED {len(unverified)}, component/dynamic {exempt}, wired-but-unmapped {len(not_in_map)}, "
|
|
175
|
+
f"value gaps {len(gaps)} ({len(no_legacy)} hard), untranslated {len(untranslated)}",
|
|
176
|
+
file=sys.stderr,
|
|
177
|
+
)
|
|
178
|
+
for item in unverified[:12]:
|
|
179
|
+
print(f"# UNVERIFIED {item['key']} ({item['element']})", file=sys.stderr)
|
|
180
|
+
for key in not_in_map[:12]:
|
|
181
|
+
print(f"# wired but unmapped: {key}", file=sys.stderr)
|
|
182
|
+
if hard:
|
|
183
|
+
print(f"# FAIL: {hard} hard issue(s); fix them or record a conscious waiver before publishing", file=sys.stderr)
|
|
184
|
+
sys.exit(2)
|
|
185
|
+
print("# PASS", file=sys.stderr)
|
|
170
186
|
|
|
171
187
|
|
|
172
188
|
if __name__ == "__main__":
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: nextjs-app-router
|
|
3
3
|
description: "Next.js 15+ App Router: Server/Client Components, Server Actions, data fetching, layouts, middleware, ISR/SSG/SSR, and routing patterns. Use when building or reviewing App Router work: Server Components, Server Actions, data fetching, layouts."
|
|
4
4
|
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
5
6
|
tags: [nextjs, react, frontend, ssr, app-router, full-stack]
|
|
6
7
|
version: "2025.1"
|
|
7
8
|
---
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: play-store-review
|
|
3
3
|
description: "Prepare Android apps for Google Play Store review and compliance. Covers Google Play policy requirements, content rating questionnaire, target API level requirements, data safety section, privacy policy requirements, in-app purchase policies, common rejection reasons, app signing with Play App Signing, and AAB upload. Use when preparing for Play Store submission, handling policy violations, or auditing app compliance."
|
|
4
|
+
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# Google Play Store Review
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: python-patterns
|
|
3
3
|
description: "Modern Python 3.12+: type hints, dataclasses, Pydantic v2, async/await, context managers, generators, pattern matching. Use when writing or reviewing modern Python: typing, dataclasses, Pydantic, async, generators."
|
|
4
4
|
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
5
6
|
tags: [python, type-hints, pydantic, asyncio, dataclasses, backend]
|
|
6
7
|
version: "2025.1"
|
|
7
8
|
---
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: react-best-practices
|
|
3
3
|
description: "React 19+ best practices: Server Components, use() hook, Actions, hooks patterns, state management, and performance optimization. Use when building or reviewing React work: components, hooks, state, Server Components, Actions."
|
|
4
4
|
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
5
6
|
tags: [react, frontend, javascript, typescript, hooks, state-management]
|
|
6
7
|
version: "2025.1"
|
|
7
8
|
---
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: rest-api-design
|
|
3
3
|
description: "REST API design: HTTP methods, status codes, pagination, versioning, rate limiting, caching headers, OpenAPI documentation. Use when a REST surface needs designing or reviewing: methods, status codes, pagination, versioning, caching."
|
|
4
4
|
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
5
6
|
tags: [rest, api, http, openapi, pagination, backend]
|
|
6
7
|
version: "2025.1"
|
|
7
8
|
---
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: retrofit-networking
|
|
3
3
|
description: "Build networking layers on Android with Retrofit, OkHttp, and Kotlin Coroutines. Covers suspend functions in API interfaces, OkHttp interceptors (auth, logging, retry), sealed Result error handling, multipart uploads, WebSocket support, network-bound resource pattern (cache + API), and Hilt integration for Retrofit instances. Use when building API clients, handling network errors, implementing caching, or setting up networking infrastructure."
|
|
4
|
+
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# Retrofit Networking
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: room-database
|
|
3
3
|
description: "Implement Room database persistence on Android with @Entity, @Dao, @Database, Flow-based reactive queries, TypeConverters for complex types, migration strategies (auto and manual), relations with @Embedded/@Relation and junction tables, in-memory database testing, and Hilt integration. Use when adding local persistence, defining database schemas, writing DAOs, handling migrations, or testing Room queries."
|
|
4
|
+
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# Room Database
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: signal-community
|
|
3
3
|
description: "Check whether other people hit the same problem, via Stack Overflow and Hacker News (keyless) plus opt-in Reddit and X. Use when a bug report or complaint needs corroboration beyond one user. Advisory only: it belongs in a risks section, never in a business rule."
|
|
4
|
+
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# Community signal
|
|
@@ -1,49 +1,88 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skill-creator
|
|
3
|
-
description: "
|
|
3
|
+
description: "House guide for authoring plugin skills: creating a new skill, trimming or splitting a bloated one, writing or sharpening a description, and choosing between a skill, slash command, subagent, CLAUDE.md entry or MCP server. Covers the lean-index SKILL.md, progressive disclosure into bundled files, the reference vs workflow vs tool split, naming without a platform prefix, growing skills from observed failures, and the pre-ship audit. Ships templates, a checklist and description examples. Use for 'write a new skill', 'this skill is too long', 'improve this skill description', 'should this be a skill or an agent'. Not for writing the domain content itself, prompt writing unrelated to plugin skills, or per-session facts that belong in CLAUDE.md."
|
|
4
4
|
user-invocable: true
|
|
5
|
-
argument-hint: [new | trim | description]
|
|
5
|
+
argument-hint: "[new | trim | description]"
|
|
6
6
|
allowed-tools: Read, Write, Edit, Glob
|
|
7
7
|
metadata:
|
|
8
8
|
version: 1.0.0
|
|
9
|
+
source: multi-agent-pipeline
|
|
9
10
|
---
|
|
10
11
|
|
|
11
|
-
# skill-creator -
|
|
12
|
-
|
|
13
|
-
> **Layer:**
|
|
14
|
-
> **
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
12
|
+
# skill-creator - authoring plugin skills
|
|
13
|
+
|
|
14
|
+
> **Layer:** knowledge (reference). **Use when:** creating, trimming, splitting, naming or describing a plugin skill, or gating one before it ships.
|
|
15
|
+
> **Not for:** the domain content inside a skill (hand that to the domain skill), prompt writing unrelated to plugin skills, or facts every session needs (those go in CLAUDE.md).
|
|
16
|
+
|
|
17
|
+
Bundled, read when the step needs it:
|
|
18
|
+
|
|
19
|
+
- [template.md](template.md) - reference and workflow skeletons with frontmatter.
|
|
20
|
+
- [checklist.md](checklist.md) - the pre-ship checklist.
|
|
21
|
+
- [examples.md](examples.md) - weak and strong descriptions, wrong and right layer shapes.
|
|
22
|
+
- [audit.md](audit.md) - the multi-architect audit loop and its lens sets; driven by `scripts/audit-panel.js`.
|
|
23
|
+
- [label-check.md](label-check.md) - the fresh-subagent inference test for names and rule labels.
|
|
24
|
+
|
|
25
|
+
## Arguments
|
|
26
|
+
|
|
27
|
+
| Argument | Start at |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `new` | Pick the artifact, write the description, then the template |
|
|
30
|
+
| `trim` | Leanness and the cut test, then the checklist |
|
|
31
|
+
| `description` | The description recipe and examples.md |
|
|
32
|
+
|
|
33
|
+
## Pick the artifact first
|
|
34
|
+
|
|
35
|
+
| Artifact | Holds |
|
|
36
|
+
|---|---|
|
|
37
|
+
| CLAUDE.md | facts and rules that are true in every session |
|
|
38
|
+
| Skill | a procedure or body of knowledge for a recurring task, loaded on demand |
|
|
39
|
+
| Subagent | work that needs its own reasoning, context window and tool set |
|
|
40
|
+
| MCP server | a structured integration with an external API |
|
|
41
|
+
|
|
42
|
+
## The description is the skill's only advertisement
|
|
43
|
+
|
|
44
|
+
Before a skill loads, the model sees its name and description and nothing else. Write the description before the body. It needs:
|
|
45
|
+
|
|
46
|
+
- **what** the skill covers or does, and **when** to use it;
|
|
47
|
+
- concrete **trigger phrases** a user would actually type, plus one sample request;
|
|
48
|
+
- the **platform** where it matters (iOS/SwiftUI, Compose, backend);
|
|
49
|
+
- an implied **boundary** against sibling skills;
|
|
50
|
+
- third person throughout.
|
|
51
|
+
|
|
52
|
+
Anthropic's measurements: a specific description instead of a vague one lifted activation from about 20% to about 50%; adding examples took it from about 72% to about 90%. A one-liner with no when, no triggers and no platform gives the router nothing to match. See examples.md.
|
|
53
|
+
|
|
54
|
+
## Keep SKILL.md an index
|
|
55
|
+
|
|
56
|
+
- Everything in SKILL.md sits in context for every turn after it loads. Aim for about one page; 500 lines is the hard ceiling.
|
|
57
|
+
- Push detail into bundled files **one level below** SKILL.md (reference, examples, scripts). They cost nothing until read. A file reached only through another bundled file tends to be read in part, so do not nest.
|
|
58
|
+
- Deterministic work belongs in a script. Running it keeps its source out of context; never ask the model to write that code again each time.
|
|
59
|
+
- **Cut test:** keep a line only if Claude would get the task wrong without it. Do not explain what the model already knows: a paragraph on how PDFs are structured loses to "use pdfplumber".
|
|
60
|
+
|
|
61
|
+
## Layer sets the degrees of freedom
|
|
62
|
+
|
|
63
|
+
| Layer | Voice | Contains | Never contains |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| reference | descriptive | invariants, conventions pointing at canonical files, decision heuristics, pitfalls, escape hatches | numbered procedures |
|
|
66
|
+
| workflow | imperative | numbered steps only for deterministic or irreversible actions (branch and PR, codegen, build and verify), citations of reference skills for judgement, a verification gate | open-ended judgement dressed as steps |
|
|
67
|
+
| tool | index | when to use, the run command, a sub-command overview; heavy detail in a bundled `reference.md`; the script is the engine | the engine's logic in prose |
|
|
68
|
+
|
|
69
|
+
`tools/figma-utility` in the iOS toolkit is the model tool skill.
|
|
70
|
+
|
|
71
|
+
## Naming
|
|
72
|
+
|
|
73
|
+
- No platform prefix: the toolkit name and the description already say it.
|
|
74
|
+
- Reference skills take an aspect noun (`navigation`); workflow skills a verb phrase (`branch-and-pr`).
|
|
75
|
+
- Avoid vague or reserved names: `helper`, `utils`, anything starting with `claude-`.
|
|
76
|
+
- When a name, title or strict-rule label has to carry its whole intent, run the label check before committing to it.
|
|
77
|
+
|
|
78
|
+
## Grow skills from failures
|
|
79
|
+
|
|
80
|
+
1. Do the task with no skill and note exactly where Claude goes wrong.
|
|
81
|
+
2. Write the smallest skill that fixes those failures. Nothing speculative.
|
|
82
|
+
3. Watch real use: promote detail that keeps getting read into SKILL.md, cut what is ignored, and sharpen the description whenever the skill failed to trigger.
|
|
83
|
+
|
|
84
|
+
## Before it ships
|
|
85
|
+
|
|
86
|
+
1. Run checklist.md as the self-review floor.
|
|
87
|
+
2. New or substantially changed skill: run the audit loop in audit.md until `clearsBar` is true.
|
|
88
|
+
3. Wire it: add the path to the `skills` array in `<plugin>/.claude-plugin/plugin.json`, bump the plugin version in `.github/plugin/marketplace.json`, and add a row to the plugin's `index` skill route table.
|