@robot-inventor/agent-skills 0.0.0 → 0.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/LICENSE +21 -21
- package/README.md +31 -31
- package/package.json +33 -33
- package/plugin.json +11 -11
- package/scripts/opencode.ts +26 -26
- package/skills/cleanup-changes/SKILL.md +33 -33
- package/skills/identify-search-maintenance/SKILL.md +78 -78
- package/skills/identify-search-maintenance/references/selection-rubric.md +45 -45
- package/skills/identify-search-maintenance/scripts/select_rank_led_candidates.py +212 -212
- package/skills/prove-it-diagnostics/SKILL.md +60 -60
- package/skills/review-loop/SKILL.md +45 -45
- package/skills/simple-engineering/SKILL.md +27 -27
- package/skills/web-master/SKILL.md +109 -109
|
@@ -1,212 +1,212 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Screen normalized Search Console page data for rank-led traffic-loss candidates."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import argparse
|
|
7
|
-
import csv
|
|
8
|
-
import math
|
|
9
|
-
import sys
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Iterable, TextIO
|
|
12
|
-
|
|
13
|
-
REQUIRED_COLUMNS = (
|
|
14
|
-
"url",
|
|
15
|
-
"current_clicks",
|
|
16
|
-
"previous_clicks",
|
|
17
|
-
"current_impressions",
|
|
18
|
-
"previous_impressions",
|
|
19
|
-
"current_position",
|
|
20
|
-
"previous_position",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def parse_number(value: str, column: str, row_number: int) -> float:
|
|
25
|
-
try:
|
|
26
|
-
number = float(value.replace(",", "").strip())
|
|
27
|
-
except (AttributeError, ValueError) as error:
|
|
28
|
-
raise ValueError(
|
|
29
|
-
f"Row {row_number}: {column} must be numeric, got {value!r}."
|
|
30
|
-
) from error
|
|
31
|
-
if not math.isfinite(number):
|
|
32
|
-
raise ValueError(f"Row {row_number}: {column} must be finite, got {value!r}.")
|
|
33
|
-
if (column.endswith("clicks") or column.endswith("impressions")) and number < 0:
|
|
34
|
-
raise ValueError(
|
|
35
|
-
f"Row {row_number}: {column} cannot be negative, got {value!r}."
|
|
36
|
-
)
|
|
37
|
-
if column.endswith("position") and number <= 0:
|
|
38
|
-
raise ValueError(
|
|
39
|
-
f"Row {row_number}: {column} must be greater than zero, got {value!r}."
|
|
40
|
-
)
|
|
41
|
-
return number
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def percentage_change(current: float, previous: float) -> float:
|
|
45
|
-
return (current - previous) / previous
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def read_rows(stream: TextIO) -> Iterable[dict[str, str]]:
|
|
49
|
-
reader = csv.DictReader(stream)
|
|
50
|
-
if reader.fieldnames is None:
|
|
51
|
-
raise ValueError("Input CSV has no header row.")
|
|
52
|
-
|
|
53
|
-
reader.fieldnames[0] = reader.fieldnames[0].lstrip("\ufeff")
|
|
54
|
-
missing = [column for column in REQUIRED_COLUMNS if column not in reader.fieldnames]
|
|
55
|
-
if missing:
|
|
56
|
-
raise ValueError(
|
|
57
|
-
f"Input CSV is missing required columns: {', '.join(missing)}."
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
return reader
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def select_candidates(
|
|
64
|
-
rows: Iterable[dict[str, str]],
|
|
65
|
-
min_previous_clicks: float,
|
|
66
|
-
max_click_change: float,
|
|
67
|
-
max_absolute_impression_change: float,
|
|
68
|
-
min_position_worsening: float,
|
|
69
|
-
min_click_gap_vs_impressions: float,
|
|
70
|
-
) -> list[dict[str, float | str]]:
|
|
71
|
-
candidates: list[dict[str, float | str]] = []
|
|
72
|
-
seen_urls: set[str] = set()
|
|
73
|
-
for row_number, row in enumerate(rows, start=2):
|
|
74
|
-
url = row["url"].strip()
|
|
75
|
-
if not url:
|
|
76
|
-
raise ValueError(f"Row {row_number}: url cannot be empty.")
|
|
77
|
-
if url in seen_urls:
|
|
78
|
-
raise ValueError(
|
|
79
|
-
f"Row {row_number}: duplicate url {url!r}; aggregate the export first."
|
|
80
|
-
)
|
|
81
|
-
seen_urls.add(url)
|
|
82
|
-
values = {
|
|
83
|
-
column: parse_number(row[column], column, row_number)
|
|
84
|
-
for column in REQUIRED_COLUMNS[1:]
|
|
85
|
-
}
|
|
86
|
-
previous_clicks = values["previous_clicks"]
|
|
87
|
-
previous_impressions = values["previous_impressions"]
|
|
88
|
-
if previous_clicks <= 0 or previous_impressions <= 0:
|
|
89
|
-
continue
|
|
90
|
-
|
|
91
|
-
click_change = percentage_change(values["current_clicks"], previous_clicks)
|
|
92
|
-
impression_change = percentage_change(
|
|
93
|
-
values["current_impressions"], previous_impressions
|
|
94
|
-
)
|
|
95
|
-
position_worsening = values["current_position"] - values["previous_position"]
|
|
96
|
-
click_gap_vs_impressions = impression_change - click_change
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
previous_clicks >= min_previous_clicks
|
|
100
|
-
and click_change <= max_click_change
|
|
101
|
-
and abs(impression_change) <= max_absolute_impression_change
|
|
102
|
-
and position_worsening >= min_position_worsening
|
|
103
|
-
and click_gap_vs_impressions >= min_click_gap_vs_impressions
|
|
104
|
-
):
|
|
105
|
-
candidates.append(
|
|
106
|
-
{
|
|
107
|
-
"url": url,
|
|
108
|
-
"current_clicks": values["current_clicks"],
|
|
109
|
-
"previous_clicks": previous_clicks,
|
|
110
|
-
"click_change": click_change,
|
|
111
|
-
"current_impressions": values["current_impressions"],
|
|
112
|
-
"previous_impressions": previous_impressions,
|
|
113
|
-
"impression_change": impression_change,
|
|
114
|
-
"current_position": values["current_position"],
|
|
115
|
-
"previous_position": values["previous_position"],
|
|
116
|
-
"position_worsening": position_worsening,
|
|
117
|
-
"click_gap_vs_impressions": click_gap_vs_impressions,
|
|
118
|
-
}
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
return sorted(
|
|
122
|
-
candidates,
|
|
123
|
-
key=lambda candidate: (
|
|
124
|
-
float(candidate["previous_clicks"]) - float(candidate["current_clicks"])
|
|
125
|
-
),
|
|
126
|
-
reverse=True,
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def percentage(value: float) -> str:
|
|
131
|
-
return f"{value * 100:.1f}%"
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def markdown(candidates: Iterable[dict[str, float | str]]) -> str:
|
|
135
|
-
lines = [
|
|
136
|
-
"| URL | Clicks (current / previous) | Click change | Impressions change | Position worsening |",
|
|
137
|
-
"| --- | ---: | ---: | ---: | ---: |",
|
|
138
|
-
]
|
|
139
|
-
for candidate in candidates:
|
|
140
|
-
lines.append(
|
|
141
|
-
"| {url} | {current_clicks:.0f} / {previous_clicks:.0f} | {click_change} | {impression_change} | {position_worsening:+.1f} |".format(
|
|
142
|
-
url=candidate["url"],
|
|
143
|
-
current_clicks=float(candidate["current_clicks"]),
|
|
144
|
-
previous_clicks=float(candidate["previous_clicks"]),
|
|
145
|
-
click_change=percentage(float(candidate["click_change"])),
|
|
146
|
-
impression_change=percentage(float(candidate["impression_change"])),
|
|
147
|
-
position_worsening=float(candidate["position_worsening"]),
|
|
148
|
-
)
|
|
149
|
-
)
|
|
150
|
-
return "\n".join(lines)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def main() -> int:
|
|
154
|
-
parser = argparse.ArgumentParser(description=__doc__)
|
|
155
|
-
parser.add_argument(
|
|
156
|
-
"input", help="Normalized CSV path, or - to read CSV from standard input."
|
|
157
|
-
)
|
|
158
|
-
parser.add_argument("--min-previous-clicks", type=float, default=100)
|
|
159
|
-
parser.add_argument("--max-click-change", type=float, default=-0.20)
|
|
160
|
-
parser.add_argument("--max-absolute-impression-change", type=float, default=0.25)
|
|
161
|
-
parser.add_argument("--min-position-worsening", type=float, default=0.5)
|
|
162
|
-
parser.add_argument("--min-click-gap-vs-impressions", type=float, default=0.10)
|
|
163
|
-
parser.add_argument("--format", choices=("markdown", "csv"), default="markdown")
|
|
164
|
-
arguments = parser.parse_args()
|
|
165
|
-
|
|
166
|
-
try:
|
|
167
|
-
if arguments.input == "-":
|
|
168
|
-
candidates = select_candidates(
|
|
169
|
-
read_rows(sys.stdin),
|
|
170
|
-
arguments.min_previous_clicks,
|
|
171
|
-
arguments.max_click_change,
|
|
172
|
-
arguments.max_absolute_impression_change,
|
|
173
|
-
arguments.min_position_worsening,
|
|
174
|
-
arguments.min_click_gap_vs_impressions,
|
|
175
|
-
)
|
|
176
|
-
else:
|
|
177
|
-
with Path(arguments.input).open(
|
|
178
|
-
encoding="utf-8-sig", newline=""
|
|
179
|
-
) as input_file:
|
|
180
|
-
candidates = select_candidates(
|
|
181
|
-
read_rows(input_file),
|
|
182
|
-
arguments.min_previous_clicks,
|
|
183
|
-
arguments.max_click_change,
|
|
184
|
-
arguments.max_absolute_impression_change,
|
|
185
|
-
arguments.min_position_worsening,
|
|
186
|
-
arguments.min_click_gap_vs_impressions,
|
|
187
|
-
)
|
|
188
|
-
except (OSError, ValueError, csv.Error) as error:
|
|
189
|
-
parser.error(str(error))
|
|
190
|
-
|
|
191
|
-
if arguments.format == "markdown":
|
|
192
|
-
print(markdown(candidates))
|
|
193
|
-
return 0
|
|
194
|
-
|
|
195
|
-
writer = csv.DictWriter(
|
|
196
|
-
sys.stdout,
|
|
197
|
-
fieldnames=(
|
|
198
|
-
"url",
|
|
199
|
-
*REQUIRED_COLUMNS[1:],
|
|
200
|
-
"click_change",
|
|
201
|
-
"impression_change",
|
|
202
|
-
"position_worsening",
|
|
203
|
-
"click_gap_vs_impressions",
|
|
204
|
-
),
|
|
205
|
-
)
|
|
206
|
-
writer.writeheader()
|
|
207
|
-
writer.writerows(candidates)
|
|
208
|
-
return 0
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if __name__ == "__main__":
|
|
212
|
-
raise SystemExit(main())
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Screen normalized Search Console page data for rank-led traffic-loss candidates."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import csv
|
|
8
|
+
import math
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Iterable, TextIO
|
|
12
|
+
|
|
13
|
+
REQUIRED_COLUMNS = (
|
|
14
|
+
"url",
|
|
15
|
+
"current_clicks",
|
|
16
|
+
"previous_clicks",
|
|
17
|
+
"current_impressions",
|
|
18
|
+
"previous_impressions",
|
|
19
|
+
"current_position",
|
|
20
|
+
"previous_position",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def parse_number(value: str, column: str, row_number: int) -> float:
|
|
25
|
+
try:
|
|
26
|
+
number = float(value.replace(",", "").strip())
|
|
27
|
+
except (AttributeError, ValueError) as error:
|
|
28
|
+
raise ValueError(
|
|
29
|
+
f"Row {row_number}: {column} must be numeric, got {value!r}."
|
|
30
|
+
) from error
|
|
31
|
+
if not math.isfinite(number):
|
|
32
|
+
raise ValueError(f"Row {row_number}: {column} must be finite, got {value!r}.")
|
|
33
|
+
if (column.endswith("clicks") or column.endswith("impressions")) and number < 0:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"Row {row_number}: {column} cannot be negative, got {value!r}."
|
|
36
|
+
)
|
|
37
|
+
if column.endswith("position") and number <= 0:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
f"Row {row_number}: {column} must be greater than zero, got {value!r}."
|
|
40
|
+
)
|
|
41
|
+
return number
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def percentage_change(current: float, previous: float) -> float:
|
|
45
|
+
return (current - previous) / previous
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def read_rows(stream: TextIO) -> Iterable[dict[str, str]]:
|
|
49
|
+
reader = csv.DictReader(stream)
|
|
50
|
+
if reader.fieldnames is None:
|
|
51
|
+
raise ValueError("Input CSV has no header row.")
|
|
52
|
+
|
|
53
|
+
reader.fieldnames[0] = reader.fieldnames[0].lstrip("\ufeff")
|
|
54
|
+
missing = [column for column in REQUIRED_COLUMNS if column not in reader.fieldnames]
|
|
55
|
+
if missing:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
f"Input CSV is missing required columns: {', '.join(missing)}."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return reader
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def select_candidates(
|
|
64
|
+
rows: Iterable[dict[str, str]],
|
|
65
|
+
min_previous_clicks: float,
|
|
66
|
+
max_click_change: float,
|
|
67
|
+
max_absolute_impression_change: float,
|
|
68
|
+
min_position_worsening: float,
|
|
69
|
+
min_click_gap_vs_impressions: float,
|
|
70
|
+
) -> list[dict[str, float | str]]:
|
|
71
|
+
candidates: list[dict[str, float | str]] = []
|
|
72
|
+
seen_urls: set[str] = set()
|
|
73
|
+
for row_number, row in enumerate(rows, start=2):
|
|
74
|
+
url = row["url"].strip()
|
|
75
|
+
if not url:
|
|
76
|
+
raise ValueError(f"Row {row_number}: url cannot be empty.")
|
|
77
|
+
if url in seen_urls:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
f"Row {row_number}: duplicate url {url!r}; aggregate the export first."
|
|
80
|
+
)
|
|
81
|
+
seen_urls.add(url)
|
|
82
|
+
values = {
|
|
83
|
+
column: parse_number(row[column], column, row_number)
|
|
84
|
+
for column in REQUIRED_COLUMNS[1:]
|
|
85
|
+
}
|
|
86
|
+
previous_clicks = values["previous_clicks"]
|
|
87
|
+
previous_impressions = values["previous_impressions"]
|
|
88
|
+
if previous_clicks <= 0 or previous_impressions <= 0:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
click_change = percentage_change(values["current_clicks"], previous_clicks)
|
|
92
|
+
impression_change = percentage_change(
|
|
93
|
+
values["current_impressions"], previous_impressions
|
|
94
|
+
)
|
|
95
|
+
position_worsening = values["current_position"] - values["previous_position"]
|
|
96
|
+
click_gap_vs_impressions = impression_change - click_change
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
previous_clicks >= min_previous_clicks
|
|
100
|
+
and click_change <= max_click_change
|
|
101
|
+
and abs(impression_change) <= max_absolute_impression_change
|
|
102
|
+
and position_worsening >= min_position_worsening
|
|
103
|
+
and click_gap_vs_impressions >= min_click_gap_vs_impressions
|
|
104
|
+
):
|
|
105
|
+
candidates.append(
|
|
106
|
+
{
|
|
107
|
+
"url": url,
|
|
108
|
+
"current_clicks": values["current_clicks"],
|
|
109
|
+
"previous_clicks": previous_clicks,
|
|
110
|
+
"click_change": click_change,
|
|
111
|
+
"current_impressions": values["current_impressions"],
|
|
112
|
+
"previous_impressions": previous_impressions,
|
|
113
|
+
"impression_change": impression_change,
|
|
114
|
+
"current_position": values["current_position"],
|
|
115
|
+
"previous_position": values["previous_position"],
|
|
116
|
+
"position_worsening": position_worsening,
|
|
117
|
+
"click_gap_vs_impressions": click_gap_vs_impressions,
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return sorted(
|
|
122
|
+
candidates,
|
|
123
|
+
key=lambda candidate: (
|
|
124
|
+
float(candidate["previous_clicks"]) - float(candidate["current_clicks"])
|
|
125
|
+
),
|
|
126
|
+
reverse=True,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def percentage(value: float) -> str:
|
|
131
|
+
return f"{value * 100:.1f}%"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def markdown(candidates: Iterable[dict[str, float | str]]) -> str:
|
|
135
|
+
lines = [
|
|
136
|
+
"| URL | Clicks (current / previous) | Click change | Impressions change | Position worsening |",
|
|
137
|
+
"| --- | ---: | ---: | ---: | ---: |",
|
|
138
|
+
]
|
|
139
|
+
for candidate in candidates:
|
|
140
|
+
lines.append(
|
|
141
|
+
"| {url} | {current_clicks:.0f} / {previous_clicks:.0f} | {click_change} | {impression_change} | {position_worsening:+.1f} |".format(
|
|
142
|
+
url=candidate["url"],
|
|
143
|
+
current_clicks=float(candidate["current_clicks"]),
|
|
144
|
+
previous_clicks=float(candidate["previous_clicks"]),
|
|
145
|
+
click_change=percentage(float(candidate["click_change"])),
|
|
146
|
+
impression_change=percentage(float(candidate["impression_change"])),
|
|
147
|
+
position_worsening=float(candidate["position_worsening"]),
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
return "\n".join(lines)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def main() -> int:
|
|
154
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
155
|
+
parser.add_argument(
|
|
156
|
+
"input", help="Normalized CSV path, or - to read CSV from standard input."
|
|
157
|
+
)
|
|
158
|
+
parser.add_argument("--min-previous-clicks", type=float, default=100)
|
|
159
|
+
parser.add_argument("--max-click-change", type=float, default=-0.20)
|
|
160
|
+
parser.add_argument("--max-absolute-impression-change", type=float, default=0.25)
|
|
161
|
+
parser.add_argument("--min-position-worsening", type=float, default=0.5)
|
|
162
|
+
parser.add_argument("--min-click-gap-vs-impressions", type=float, default=0.10)
|
|
163
|
+
parser.add_argument("--format", choices=("markdown", "csv"), default="markdown")
|
|
164
|
+
arguments = parser.parse_args()
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
if arguments.input == "-":
|
|
168
|
+
candidates = select_candidates(
|
|
169
|
+
read_rows(sys.stdin),
|
|
170
|
+
arguments.min_previous_clicks,
|
|
171
|
+
arguments.max_click_change,
|
|
172
|
+
arguments.max_absolute_impression_change,
|
|
173
|
+
arguments.min_position_worsening,
|
|
174
|
+
arguments.min_click_gap_vs_impressions,
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
with Path(arguments.input).open(
|
|
178
|
+
encoding="utf-8-sig", newline=""
|
|
179
|
+
) as input_file:
|
|
180
|
+
candidates = select_candidates(
|
|
181
|
+
read_rows(input_file),
|
|
182
|
+
arguments.min_previous_clicks,
|
|
183
|
+
arguments.max_click_change,
|
|
184
|
+
arguments.max_absolute_impression_change,
|
|
185
|
+
arguments.min_position_worsening,
|
|
186
|
+
arguments.min_click_gap_vs_impressions,
|
|
187
|
+
)
|
|
188
|
+
except (OSError, ValueError, csv.Error) as error:
|
|
189
|
+
parser.error(str(error))
|
|
190
|
+
|
|
191
|
+
if arguments.format == "markdown":
|
|
192
|
+
print(markdown(candidates))
|
|
193
|
+
return 0
|
|
194
|
+
|
|
195
|
+
writer = csv.DictWriter(
|
|
196
|
+
sys.stdout,
|
|
197
|
+
fieldnames=(
|
|
198
|
+
"url",
|
|
199
|
+
*REQUIRED_COLUMNS[1:],
|
|
200
|
+
"click_change",
|
|
201
|
+
"impression_change",
|
|
202
|
+
"position_worsening",
|
|
203
|
+
"click_gap_vs_impressions",
|
|
204
|
+
),
|
|
205
|
+
)
|
|
206
|
+
writer.writeheader()
|
|
207
|
+
writer.writerows(candidates)
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
if __name__ == "__main__":
|
|
212
|
+
raise SystemExit(main())
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: prove-it-diagnostics
|
|
3
|
-
description: Prove it for debugging, performance investigation, bottleneck analysis, profiling, and optimization work. When reading code does not prove the cause, run a minimal reproduction, add temporary traces, measure bottlenecks, and verify the fix or improvement.
|
|
4
|
-
license: MIT
|
|
5
|
-
metadata:
|
|
6
|
-
author: Robot-Inventor
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Prove It Diagnostics
|
|
10
|
-
|
|
11
|
-
Use this skill to pinpoint the causes of bugs and performance bottlenecks and fix them. Reading code alone may not reveal the source of a bug or bottleneck. Do not claim that a speculative code change fixed a bug or improved performance. Run the code, gather evidence, identify the cause, and verify the fix.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
The following is the core of this skill; please follow the specified steps.
|
|
16
|
-
|
|
17
|
-
## 1. Establish a performance baseline for optimization tasks
|
|
18
|
-
|
|
19
|
-
For performance optimization tasks, create and run a benchmark before making changes. Run the benchmark as many times as practical. Use averages, percentiles, and other relevant statistics to establish a stable baseline instead of relying on a single run.
|
|
20
|
-
|
|
21
|
-
## 2. Read the code
|
|
22
|
-
|
|
23
|
-
Read the code related to the bug or performance issue. For debugging tasks, you may fix the issue and skip the remaining steps when you find a clear cause, such as an incorrect operator or an obvious contradiction in the logic.
|
|
24
|
-
|
|
25
|
-
Continue with the remaining steps when you cannot identify the cause with confidence or when you find suspicious code but lack enough evidence to blame it.
|
|
26
|
-
|
|
27
|
-
### 3. Verify the cause
|
|
28
|
-
|
|
29
|
-
Do not rely on code inspection alone. Run experiments to identify the source of the bug or bottleneck.
|
|
30
|
-
|
|
31
|
-
For debugging tasks:
|
|
32
|
-
|
|
33
|
-
1. Create a reproduction in a temporary file or REPL and run it to confirm the bug. If the reproduction does not fail, add relevant behavior from the target code until it reproduces the bug.
|
|
34
|
-
2. Remove or revert each part of the reproduction to find the smallest program that still triggers the bug. A minimal reproduction narrows the list of possible causes.
|
|
35
|
-
3. Investigate the minimal reproduction, identify the cause, and fix it. Address the root cause instead of applying a superficial workaround, as described in the Rules section.
|
|
36
|
-
4. Confirm that the fix prevents the bug in the minimal reproduction.
|
|
37
|
-
5. Apply the fix to the production code and confirm that it resolves the original bug. If the bug remains, return to the reproduction step and repeat the process.
|
|
38
|
-
|
|
39
|
-
For performance optimization tasks:
|
|
40
|
-
|
|
41
|
-
1. Use benchmarks, profilers, timing logs, or similar tools to identify the slow operation.
|
|
42
|
-
2. Fix the bottleneck, then use the same measurements to confirm that performance improved.
|
|
43
|
-
3. Apply the fix to the production code and confirm the improvement there. If performance does not improve, return to bottleneck analysis and repeat the process.
|
|
44
|
-
|
|
45
|
-
### 4. Clean up
|
|
46
|
-
|
|
47
|
-
Remove temporary logs, reproduction code, generated files, and log data created during verification.
|
|
48
|
-
|
|
49
|
-
## Rules
|
|
50
|
-
|
|
51
|
-
If a user reports that your fix did not resolve the bug or improve performance, treat your previous diagnosis as unverified and restart the investigation.
|
|
52
|
-
|
|
53
|
-
Surface-level and stop-gap fixes are shameful; identify and fix the root cause. For example, when an error triggers a bug, find and fix the source of the error instead of adding a fallback for the failure. Keep asking yourself, “Is this the root cause?”
|
|
54
|
-
|
|
55
|
-
When evidence points to a bug in a dependency, do not patch the dependency. Tell the user that the dependency appears to contain a bug, describe the evidence, and propose changes they can make in their project without modifying the dependency.
|
|
56
|
-
|
|
57
|
-
When you get stuck, try these approaches:
|
|
58
|
-
|
|
59
|
-
- Add temporary logs across the affected path. Use them to find the boundary between correct and incorrect behavior, or between fast and slow execution.
|
|
60
|
-
- When behavior contradicts the code’s logic or you cannot make progress, search the relevant library’s GitHub issues and pull requests, Stack Overflow, and community articles for reports of the same problem and possible solutions.
|
|
1
|
+
---
|
|
2
|
+
name: prove-it-diagnostics
|
|
3
|
+
description: Prove it for debugging, performance investigation, bottleneck analysis, profiling, and optimization work. When reading code does not prove the cause, run a minimal reproduction, add temporary traces, measure bottlenecks, and verify the fix or improvement.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Robot-Inventor
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Prove It Diagnostics
|
|
10
|
+
|
|
11
|
+
Use this skill to pinpoint the causes of bugs and performance bottlenecks and fix them. Reading code alone may not reveal the source of a bug or bottleneck. Do not claim that a speculative code change fixed a bug or improved performance. Run the code, gather evidence, identify the cause, and verify the fix.
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
The following is the core of this skill; please follow the specified steps.
|
|
16
|
+
|
|
17
|
+
## 1. Establish a performance baseline for optimization tasks
|
|
18
|
+
|
|
19
|
+
For performance optimization tasks, create and run a benchmark before making changes. Run the benchmark as many times as practical. Use averages, percentiles, and other relevant statistics to establish a stable baseline instead of relying on a single run.
|
|
20
|
+
|
|
21
|
+
## 2. Read the code
|
|
22
|
+
|
|
23
|
+
Read the code related to the bug or performance issue. For debugging tasks, you may fix the issue and skip the remaining steps when you find a clear cause, such as an incorrect operator or an obvious contradiction in the logic.
|
|
24
|
+
|
|
25
|
+
Continue with the remaining steps when you cannot identify the cause with confidence or when you find suspicious code but lack enough evidence to blame it.
|
|
26
|
+
|
|
27
|
+
### 3. Verify the cause
|
|
28
|
+
|
|
29
|
+
Do not rely on code inspection alone. Run experiments to identify the source of the bug or bottleneck.
|
|
30
|
+
|
|
31
|
+
For debugging tasks:
|
|
32
|
+
|
|
33
|
+
1. Create a reproduction in a temporary file or REPL and run it to confirm the bug. If the reproduction does not fail, add relevant behavior from the target code until it reproduces the bug.
|
|
34
|
+
2. Remove or revert each part of the reproduction to find the smallest program that still triggers the bug. A minimal reproduction narrows the list of possible causes.
|
|
35
|
+
3. Investigate the minimal reproduction, identify the cause, and fix it. Address the root cause instead of applying a superficial workaround, as described in the Rules section.
|
|
36
|
+
4. Confirm that the fix prevents the bug in the minimal reproduction.
|
|
37
|
+
5. Apply the fix to the production code and confirm that it resolves the original bug. If the bug remains, return to the reproduction step and repeat the process.
|
|
38
|
+
|
|
39
|
+
For performance optimization tasks:
|
|
40
|
+
|
|
41
|
+
1. Use benchmarks, profilers, timing logs, or similar tools to identify the slow operation.
|
|
42
|
+
2. Fix the bottleneck, then use the same measurements to confirm that performance improved.
|
|
43
|
+
3. Apply the fix to the production code and confirm the improvement there. If performance does not improve, return to bottleneck analysis and repeat the process.
|
|
44
|
+
|
|
45
|
+
### 4. Clean up
|
|
46
|
+
|
|
47
|
+
Remove temporary logs, reproduction code, generated files, and log data created during verification.
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
If a user reports that your fix did not resolve the bug or improve performance, treat your previous diagnosis as unverified and restart the investigation.
|
|
52
|
+
|
|
53
|
+
Surface-level and stop-gap fixes are shameful; identify and fix the root cause. For example, when an error triggers a bug, find and fix the source of the error instead of adding a fallback for the failure. Keep asking yourself, “Is this the root cause?”
|
|
54
|
+
|
|
55
|
+
When evidence points to a bug in a dependency, do not patch the dependency. Tell the user that the dependency appears to contain a bug, describe the evidence, and propose changes they can make in their project without modifying the dependency.
|
|
56
|
+
|
|
57
|
+
When you get stuck, try these approaches:
|
|
58
|
+
|
|
59
|
+
- Add temporary logs across the affected path. Use them to find the boundary between correct and incorrect behavior, or between fast and slow execution.
|
|
60
|
+
- When behavior contradicts the code’s logic or you cannot make progress, search the relevant library’s GitHub issues and pull requests, Stack Overflow, and community articles for reports of the same problem and possible solutions.
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: review-loop
|
|
3
|
-
description: Thoroughly improve code quality by requesting a review from a sub-agent after completing tasks requiring code editing, before returning the conversation turn to the user. Use for any task that edits code or configuration. Read this skill before starting edits, and after completing the requested changes run an isolated sub-agent review loop before returning the final response.
|
|
4
|
-
license: MIT
|
|
5
|
-
metadata:
|
|
6
|
-
author: Robot-Inventor
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Review Loop Skill
|
|
10
|
-
|
|
11
|
-
This skill involves thoroughly improving code quality by repeatedly requesting a review from a sub-agent after editing and improving the code based on the results. Humans typically improve code quality by creating a pull request after editing code and having it reviewed by a reviewer. Such reviews are important because they can identify problems that might be missed through self-review alone.
|
|
12
|
-
|
|
13
|
-
## When to apply
|
|
14
|
-
|
|
15
|
-
Apply this skill in the following situations:
|
|
16
|
-
|
|
17
|
-
- When you have performed a task that requires code editing, and
|
|
18
|
-
- After completing the task instructed by the user, and
|
|
19
|
-
- Before returning the conversation to the user
|
|
20
|
-
|
|
21
|
-
## Steps
|
|
22
|
-
|
|
23
|
-
The following is the core of this skill; please follow the specified steps.
|
|
24
|
-
|
|
25
|
-
### 1. Request a code review
|
|
26
|
-
|
|
27
|
-
Request a code review from the subagent.
|
|
28
|
-
|
|
29
|
-
If you have the option to choose whether to fork the context or launch the subagent in an isolated context when starting it, **always** launch it in an isolated context. Forking the context would be equivalent to a self-review, so you need to launch a subagent in an isolated context to review it from a different perspective.
|
|
30
|
-
|
|
31
|
-
When requesting a review from a sub-agent, be sure to provide them with an overview of the task requested by the user, and instruct them to thoroughly review the changes made to the current workspace.
|
|
32
|
-
|
|
33
|
-
### 2. Receive reviews and improve your code
|
|
34
|
-
|
|
35
|
-
Once you receive the review results from the sub-agent, consider whether each point is valid. You may ignore clearly unreasonable points, but you must address valid points and correct the code accordingly.
|
|
36
|
-
|
|
37
|
-
In particular, if you receive feedback on a part that doesn't strictly follow the user's instructions as a result of compromises, do not ignore it. Instead, correct it according to the review to align with the user's instructions as much as possible. If you absolutely cannot comply with the user's request, you may ignore the sub-agent's point about that part, but be sure to inform the user of the compromise you made when you return the conversation to them.
|
|
38
|
-
|
|
39
|
-
### 3. Review loop
|
|
40
|
-
|
|
41
|
-
After addressing valid feedback from the subagent, repeat steps 1 and 2 ("1. Request a code review" and "2. Receive reviews and improve your code") until there is no more valid feedback from the subagent, thoroughly improving your code quality. In this review loop, always have a new subagent review your code each time.
|
|
42
|
-
|
|
43
|
-
### 4. Report the results to the user
|
|
44
|
-
|
|
45
|
-
Once the review loop is complete, return the conversation to the user. Be sure to honestly report to the user any points where you had to compromise and did not strictly follow their instructions.
|
|
1
|
+
---
|
|
2
|
+
name: review-loop
|
|
3
|
+
description: Thoroughly improve code quality by requesting a review from a sub-agent after completing tasks requiring code editing, before returning the conversation turn to the user. Use for any task that edits code or configuration. Read this skill before starting edits, and after completing the requested changes run an isolated sub-agent review loop before returning the final response.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Robot-Inventor
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Review Loop Skill
|
|
10
|
+
|
|
11
|
+
This skill involves thoroughly improving code quality by repeatedly requesting a review from a sub-agent after editing and improving the code based on the results. Humans typically improve code quality by creating a pull request after editing code and having it reviewed by a reviewer. Such reviews are important because they can identify problems that might be missed through self-review alone.
|
|
12
|
+
|
|
13
|
+
## When to apply
|
|
14
|
+
|
|
15
|
+
Apply this skill in the following situations:
|
|
16
|
+
|
|
17
|
+
- When you have performed a task that requires code editing, and
|
|
18
|
+
- After completing the task instructed by the user, and
|
|
19
|
+
- Before returning the conversation to the user
|
|
20
|
+
|
|
21
|
+
## Steps
|
|
22
|
+
|
|
23
|
+
The following is the core of this skill; please follow the specified steps.
|
|
24
|
+
|
|
25
|
+
### 1. Request a code review
|
|
26
|
+
|
|
27
|
+
Request a code review from the subagent.
|
|
28
|
+
|
|
29
|
+
If you have the option to choose whether to fork the context or launch the subagent in an isolated context when starting it, **always** launch it in an isolated context. Forking the context would be equivalent to a self-review, so you need to launch a subagent in an isolated context to review it from a different perspective.
|
|
30
|
+
|
|
31
|
+
When requesting a review from a sub-agent, be sure to provide them with an overview of the task requested by the user, and instruct them to thoroughly review the changes made to the current workspace.
|
|
32
|
+
|
|
33
|
+
### 2. Receive reviews and improve your code
|
|
34
|
+
|
|
35
|
+
Once you receive the review results from the sub-agent, consider whether each point is valid. You may ignore clearly unreasonable points, but you must address valid points and correct the code accordingly.
|
|
36
|
+
|
|
37
|
+
In particular, if you receive feedback on a part that doesn't strictly follow the user's instructions as a result of compromises, do not ignore it. Instead, correct it according to the review to align with the user's instructions as much as possible. If you absolutely cannot comply with the user's request, you may ignore the sub-agent's point about that part, but be sure to inform the user of the compromise you made when you return the conversation to them.
|
|
38
|
+
|
|
39
|
+
### 3. Review loop
|
|
40
|
+
|
|
41
|
+
After addressing valid feedback from the subagent, repeat steps 1 and 2 ("1. Request a code review" and "2. Receive reviews and improve your code") until there is no more valid feedback from the subagent, thoroughly improving your code quality. In this review loop, always have a new subagent review your code each time.
|
|
42
|
+
|
|
43
|
+
### 4. Report the results to the user
|
|
44
|
+
|
|
45
|
+
Once the review loop is complete, return the conversation to the user. Be sure to honestly report to the user any points where you had to compromise and did not strictly follow their instructions.
|