codex-harness-engineering 0.1.4 → 0.1.6
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/AGENTS.md +18 -6
- package/LICENSE +21 -0
- package/README.md +69 -6
- package/docs/harness-engineering/implementation-playbook.md +232 -286
- package/docs/harness-engineering/index.md +7 -4
- package/docs/harness-engineering/research-note.md +294 -274
- package/docs/harness-engineering/sources.md +166 -72
- package/package.json +9 -4
- package/scripts/install-skills.mjs +73 -15
- package/scripts/publish.sh +2 -2
- package/scripts/verify-harness.mjs +61 -4
- package/skills/acceptance-contract/SKILL.md +39 -49
- package/skills/acceptance-contract/agents/openai.yaml +2 -2
- package/skills/cleanup-harness/SKILL.md +48 -59
- package/skills/cleanup-harness/agents/openai.yaml +2 -2
- package/skills/creator-harness/SKILL.md +79 -95
- package/skills/creator-harness/agents/openai.yaml +2 -2
- package/skills/creator-harness/references/harness-artifacts.md +63 -62
- package/skills/lessons-harness/SKILL.md +68 -0
- package/skills/lessons-harness/agents/openai.yaml +4 -0
- package/templates/harness/AGENTS.md +77 -0
- package/templates/harness/feature_list.json +16 -0
- package/templates/harness/init.sh +15 -0
- package/templates/harness/lessons.md +18 -0
- package/templates/harness/memory/README.md +22 -0
- package/templates/harness/progress.md +33 -0
- package/templates/harness/rotate-state.mjs +131 -0
- package/templates/harness/verify-state.mjs +117 -0
- package/templates/team/roles/evaluator.md +43 -0
- package/templates/team/roles/implementer.md +29 -0
- package/templates/team/roles/planner.md +28 -0
- package/templates/team/sprint-template.md +36 -0
- package/templates/team/verify-team.mjs +71 -0
- package/templates/team/workflow.md +62 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Mẫu Artifact Harness
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Dùng các mẫu này một cách chọn lọc. Đừng tạo mọi artifact theo mặc định.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Mỗi artifact phải trả lời ít nhất một câu hỏi:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- Agent cần biết gì?
|
|
8
|
+
- State nào sống sót qua mất context?
|
|
9
|
+
- Agent quan sát được gì?
|
|
10
|
+
- Agent verify công việc thế nào?
|
|
11
|
+
- Ràng buộc nào được cưỡng chế cơ học?
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Mục lục
|
|
14
14
|
|
|
15
|
-
-
|
|
15
|
+
- Harness repository tối thiểu
|
|
16
16
|
- AGENTS.md
|
|
17
17
|
- progress.md
|
|
18
18
|
- feature_list.json
|
|
@@ -21,11 +21,12 @@ Each artifact must answer at least one question:
|
|
|
21
21
|
- Acceptance Contract
|
|
22
22
|
- Sprint Contract
|
|
23
23
|
- Evaluator Notes
|
|
24
|
+
- Legibility Map
|
|
24
25
|
- Cleanup Task
|
|
25
26
|
|
|
26
|
-
##
|
|
27
|
+
## Harness repository tối thiểu
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
Bắt đầu từ đây trừ khi một failure mode có tên đòi hỏi nhiều hơn.
|
|
29
30
|
|
|
30
31
|
```text
|
|
31
32
|
AGENTS.md
|
|
@@ -33,11 +34,11 @@ README.md
|
|
|
33
34
|
progress.md
|
|
34
35
|
feature_list.json
|
|
35
36
|
init.sh
|
|
36
|
-
Makefile
|
|
37
|
-
tests/
|
|
37
|
+
Makefile hoặc task runner
|
|
38
|
+
tests/ hoặc smoke test
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
Chỉ thêm khi cần:
|
|
41
42
|
|
|
42
43
|
```text
|
|
43
44
|
docs/architecture.md
|
|
@@ -99,8 +100,8 @@ cleanup.md
|
|
|
99
100
|
- ...
|
|
100
101
|
```
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
Giữ mỗi entry ngắn và khôi phục được. Ưu tiên đường dẫn file, tên lệnh, tên test
|
|
104
|
+
fail, và đường dẫn artifact hơn là văn xuôi mơ hồ.
|
|
104
105
|
|
|
105
106
|
## feature_list.json
|
|
106
107
|
|
|
@@ -124,8 +125,8 @@ test names, and artifact paths over vague prose.
|
|
|
124
125
|
]
|
|
125
126
|
```
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
`verified`.
|
|
128
|
+
Dùng giá trị `status` nhất quán: `not_started`, `in_progress`, `blocked`,
|
|
129
|
+
`verified`. Chỉ đặt `verified` sau khi các kiểm tra đã liệt kê pass.
|
|
129
130
|
|
|
130
131
|
## init.sh
|
|
131
132
|
|
|
@@ -161,22 +162,22 @@ smoke:
|
|
|
161
162
|
verify: lint test build smoke
|
|
162
163
|
```
|
|
163
164
|
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
Giữ tên lệnh ổn định. Hướng dẫn cho agent nên trỏ tới các target này thay vì lặp
|
|
166
|
+
lại dòng lệnh dài qua nhiều file.
|
|
166
167
|
|
|
167
168
|
## Acceptance Contract
|
|
168
169
|
|
|
169
|
-
|
|
170
|
+
Dùng cho một bug hoặc feature nhỏ khi planner/evaluator là quá mức.
|
|
170
171
|
|
|
171
172
|
```markdown
|
|
172
173
|
# Acceptance Contract
|
|
173
174
|
|
|
174
|
-
##
|
|
175
|
+
## Phạm vi
|
|
175
176
|
- Feature/fix:
|
|
176
|
-
-
|
|
177
|
-
-
|
|
177
|
+
- Hành vi nhìn thấy phía người dùng:
|
|
178
|
+
- File có khả năng đụng đến:
|
|
178
179
|
|
|
179
|
-
##
|
|
180
|
+
## Tiêu chí nghiệm thu
|
|
180
181
|
- [ ] ...
|
|
181
182
|
- [ ] ...
|
|
182
183
|
|
|
@@ -186,28 +187,28 @@ Use this for a small bug or feature when planner/evaluator would be too much.
|
|
|
186
187
|
- Browser/API:
|
|
187
188
|
- Log/metric/trace:
|
|
188
189
|
|
|
189
|
-
##
|
|
190
|
+
## Ngoài phạm vi
|
|
190
191
|
- ...
|
|
191
192
|
```
|
|
192
193
|
|
|
193
194
|
## Sprint Contract
|
|
194
195
|
|
|
195
|
-
|
|
196
|
+
Dùng khi công việc trải qua nhiều file, hành vi runtime, hoặc chất lượng chủ quan.
|
|
196
197
|
|
|
197
198
|
```markdown
|
|
198
199
|
# Sprint Contract
|
|
199
200
|
|
|
200
|
-
##
|
|
201
|
+
## Phạm vi
|
|
201
202
|
- Feature:
|
|
202
203
|
- User path:
|
|
203
204
|
- API/data path:
|
|
204
|
-
-
|
|
205
|
+
- File/module có khả năng đụng đến:
|
|
205
206
|
|
|
206
|
-
## Done
|
|
207
|
+
## Done nghĩa là
|
|
207
208
|
- [ ] User can ...
|
|
208
|
-
- [ ] API
|
|
209
|
-
- [ ]
|
|
210
|
-
- [ ]
|
|
209
|
+
- [ ] API hoặc data phản ánh ...
|
|
210
|
+
- [ ] Trạng thái lỗi xử lý ...
|
|
211
|
+
- [ ] Không regression ở ...
|
|
211
212
|
|
|
212
213
|
## Verification
|
|
213
214
|
- Unit:
|
|
@@ -215,56 +216,56 @@ Use this when work spans multiple files, runtime behavior, or subjective quality
|
|
|
215
216
|
- Browser/API:
|
|
216
217
|
- Log/metric/trace:
|
|
217
218
|
|
|
218
|
-
## Evaluator
|
|
219
|
-
-
|
|
220
|
-
-
|
|
221
|
-
- UX
|
|
219
|
+
## Trọng tâm Evaluator
|
|
220
|
+
- Hành vi runtime:
|
|
221
|
+
- Ca âm (negative cases):
|
|
222
|
+
- Lo ngại về UX hoặc chất lượng:
|
|
222
223
|
|
|
223
|
-
##
|
|
224
|
+
## Ngoài phạm vi
|
|
224
225
|
- ...
|
|
225
226
|
```
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
Nếu sprint contract dài hơn cả phần việc, hãy chia nhỏ công việc hoặc lùi về một
|
|
229
|
+
acceptance contract nhỏ hơn.
|
|
229
230
|
|
|
230
231
|
## Evaluator Notes
|
|
231
232
|
|
|
232
|
-
|
|
233
|
+
Dùng khi generator tự review chưa đủ.
|
|
233
234
|
|
|
234
235
|
```markdown
|
|
235
236
|
# Evaluator Notes
|
|
236
237
|
|
|
237
238
|
## Contract
|
|
238
239
|
- Sprint:
|
|
239
|
-
-
|
|
240
|
+
- Hành vi kỳ vọng:
|
|
240
241
|
|
|
241
|
-
##
|
|
242
|
-
-
|
|
243
|
-
-
|
|
242
|
+
## Kiểm tra đã chạy
|
|
243
|
+
- Lệnh/kiểm tra:
|
|
244
|
+
- Kết quả:
|
|
244
245
|
- Artifact:
|
|
245
246
|
|
|
246
|
-
##
|
|
247
|
+
## Phát hiện
|
|
247
248
|
- [ ] P0/P1/P2:
|
|
248
|
-
-
|
|
249
|
+
- Bằng chứng:
|
|
249
250
|
- Repro:
|
|
250
|
-
-
|
|
251
|
+
- Bước tiếp theo đề xuất:
|
|
251
252
|
|
|
252
|
-
##
|
|
253
|
+
## Phán quyết
|
|
253
254
|
- pass/fail:
|
|
254
|
-
-
|
|
255
|
+
- Lý do:
|
|
255
256
|
```
|
|
256
257
|
|
|
257
|
-
|
|
258
|
-
response, database state,
|
|
258
|
+
Feedback của evaluator nên dẫn bằng chứng quan sát được: screenshot, DOM state,
|
|
259
|
+
API response, database state, log, trace, hoặc output của lệnh.
|
|
259
260
|
|
|
260
261
|
## Legibility Map
|
|
261
262
|
|
|
262
|
-
|
|
263
|
+
Dùng khi agent không nhìn thấy đủ hành vi runtime.
|
|
263
264
|
|
|
264
265
|
```markdown
|
|
265
266
|
# Legibility Map
|
|
266
267
|
|
|
267
|
-
|
|
|
268
|
+
| Khu vực | Tín hiệu | Cách thu thập | Owner/kiểm tra |
|
|
268
269
|
| --- | --- | --- | --- |
|
|
269
270
|
| UI | Screenshot/DOM | | |
|
|
270
271
|
| API | Request/response | | |
|
|
@@ -276,20 +277,20 @@ Use this when the agent cannot see enough runtime behavior.
|
|
|
276
277
|
|
|
277
278
|
## Cleanup Task
|
|
278
279
|
|
|
279
|
-
|
|
280
|
+
Dùng khi throughput của agent tạo ra drift lặp lại.
|
|
280
281
|
|
|
281
282
|
```markdown
|
|
282
283
|
# Cleanup Task
|
|
283
284
|
|
|
284
285
|
## Trigger
|
|
285
|
-
-
|
|
286
|
-
-
|
|
286
|
+
- Pattern lặp lại:
|
|
287
|
+
- Bằng chứng:
|
|
287
288
|
|
|
288
|
-
##
|
|
289
|
-
-
|
|
290
|
-
-
|
|
289
|
+
## Phạm vi
|
|
290
|
+
- Bao gồm:
|
|
291
|
+
- Loại trừ:
|
|
291
292
|
|
|
292
|
-
##
|
|
293
|
+
## Tiêu chí nghiệm thu
|
|
293
294
|
- [ ] ...
|
|
294
295
|
|
|
295
296
|
## Verification
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lessons-harness
|
|
3
|
+
description: Dùng khi một gate fail, regression, defect review, hoặc lỗi sửa đi sửa lại cần trở thành bài học bền vững — ghi lại lỗi, rút ra quy tắc, và đẩy các quy tắc lặp lại thành guardrail cơ học.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lessons Harness
|
|
7
|
+
|
|
8
|
+
## Điều kiện kích hoạt
|
|
9
|
+
|
|
10
|
+
Ghi một bài học vào `lessons.md` khi:
|
|
11
|
+
|
|
12
|
+
- một verify gate, test, hoặc smoke check fail vì lý do do agent gây ra;
|
|
13
|
+
- một regression xuất hiện ở hành vi trước đây vốn chạy đúng;
|
|
14
|
+
- review hoặc evaluator bắt được một lớp defect do agent tạo ra;
|
|
15
|
+
- cùng một cách sửa hoặc workaround được áp dụng lần thứ hai;
|
|
16
|
+
- một giả định sai về repo, một tool, hoặc một nguồn còn sống sót qua session
|
|
17
|
+
đã tạo ra nó.
|
|
18
|
+
|
|
19
|
+
Không ghi các fail red-green thường thấy trong TDD bình thường, hoặc flake môi
|
|
20
|
+
trường nằm ngoài tầm kiểm soát của agent.
|
|
21
|
+
|
|
22
|
+
## Quy trình
|
|
23
|
+
|
|
24
|
+
1. Viết bài học khi bối cảnh lỗi còn tươi. Mỗi mục một bài học: mistake, root
|
|
25
|
+
cause, rule, status.
|
|
26
|
+
2. Giữ rule mang tính vận hành: một hành vi hoặc kiểm tra cụ thể cho lần sau,
|
|
27
|
+
không phải ý định mơ hồ.
|
|
28
|
+
3. Tìm trong `lessons.md` và `memory/lessons/` cùng một root cause trước khi
|
|
29
|
+
thêm bản gần-trùng; nếu đã có, rule là lặp lại.
|
|
30
|
+
4. Đẩy một rule lặp lại vào dạng cơ học nhỏ nhất giữ được nó [S1], [S3]:
|
|
31
|
+
- quy tắc hành vi bền vững → một dòng rule trong `AGENTS.md`;
|
|
32
|
+
- invariant về cấu trúc hoặc style → một lint hoặc structural test;
|
|
33
|
+
- invariant về state hoặc quy trình → mở rộng verify gate;
|
|
34
|
+
- policy phức tạp → một code wrapper tổng hợp chặn hành động không hợp lệ
|
|
35
|
+
trước khi thực thi [S5].
|
|
36
|
+
5. Đổi dòng status của bài học thành `Status: promoted: <ở đâu>` rồi chạy
|
|
37
|
+
`node rotate-state.mjs` để các bài học đã promote chuyển sang
|
|
38
|
+
`memory/lessons/` và file nóng giữ nhỏ.
|
|
39
|
+
6. Ghi lần promote vào `progress.md` như mọi thay đổi hành vi khác.
|
|
40
|
+
|
|
41
|
+
## Định dạng một bài học
|
|
42
|
+
|
|
43
|
+
Mỗi mục trong `lessons.md` theo dạng sau (heading có ngày, bốn trường):
|
|
44
|
+
|
|
45
|
+
- Mistake: điều gì sai và quan sát ở đâu.
|
|
46
|
+
- Root cause: vì sao xảy ra, không chỉ là cái gì hỏng.
|
|
47
|
+
- Rule: hành vi hoặc kiểm tra ngăn nó lặp lại lần sau.
|
|
48
|
+
- Status: `pending`, hoặc `promoted: <vị trí rule hoặc gate>`.
|
|
49
|
+
|
|
50
|
+
## Hướng dẫn promote
|
|
51
|
+
|
|
52
|
+
- Ưu tiên can thiệp nhỏ nhất loại bỏ được failure mode [S3].
|
|
53
|
+
- Một rule đã promote phải bảo vệ một invariant cụ thể; đừng thêm quy tắc rộng
|
|
54
|
+
mà không ràng buộc gì.
|
|
55
|
+
- Khi verify gate có thêm một kiểm tra, thêm một regression test cho chính kiểm
|
|
56
|
+
tra đó.
|
|
57
|
+
- Bài học pending là state nóng agent đọc mỗi session; bài học đã promote là
|
|
58
|
+
lịch sử nguội. Giữ file nóng trong ngân sách dòng của nó.
|
|
59
|
+
|
|
60
|
+
## Ánh xạ nguồn
|
|
61
|
+
|
|
62
|
+
- Tri thức cục bộ trong repo sống lâu hơn session; lịch sử chat thì không [S1].
|
|
63
|
+
- Agent chạy dài cần state được externalize để khôi phục và cải thiện qua các
|
|
64
|
+
session [S2].
|
|
65
|
+
- Giữ mỗi can thiệp đơn giản đúng mức mà failure mode cho phép [S3].
|
|
66
|
+
- Chuyển phán đoán lặp lại thành kiểm tra cơ học mạnh hơn văn xuôi [S1].
|
|
67
|
+
- AutoHarness cho thấy policy có thể được tổng hợp thành code wrapper tĩnh lọc
|
|
68
|
+
hành động không hợp lệ trước khi thực thi [S5].
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
Codex reads this file at the start of every session. Keep it a short map; the
|
|
4
|
+
deeper source of truth lives in the files it points to, not in chat history.
|
|
5
|
+
|
|
6
|
+
## Start Here
|
|
7
|
+
|
|
8
|
+
1. Read `README.md`.
|
|
9
|
+
2. Read the latest entries in `progress.md` to recover what the previous
|
|
10
|
+
session did.
|
|
11
|
+
3. Check `feature_list.json` for the current capability state.
|
|
12
|
+
4. Read `lessons.md` for pending mistakes and rules from prior sessions.
|
|
13
|
+
5. Run `./init.sh` to set up and smoke-test before editing anything.
|
|
14
|
+
6. Review recent git history to see what the last session changed.
|
|
15
|
+
|
|
16
|
+
## Skills
|
|
17
|
+
|
|
18
|
+
Installed under `.agents/skills/`. Invoke with `$skill-name`:
|
|
19
|
+
|
|
20
|
+
- `$acceptance-contract` — before implementing: lock scope, done criteria, and
|
|
21
|
+
verification commands.
|
|
22
|
+
- `$creator-harness` — when this harness is missing a layer for a named
|
|
23
|
+
failure mode (lost context, invisible runtime, optimistic self-review).
|
|
24
|
+
- `$cleanup-harness` — when repeated drift, duplicate helpers, or doc rot
|
|
25
|
+
appears across sessions.
|
|
26
|
+
- `$lessons-harness` — when a verify gate, test, or review catches a mistake;
|
|
27
|
+
log it in `lessons.md` and promote recurring rules into guardrails.
|
|
28
|
+
|
|
29
|
+
## Memory Layout
|
|
30
|
+
|
|
31
|
+
Hot files are read every session; cold files are searched only when history is
|
|
32
|
+
needed. Do not let hot files grow unbounded.
|
|
33
|
+
|
|
34
|
+
- `progress.md` — hot: recent session log (latest entries only).
|
|
35
|
+
- `feature_list.json` — hot: active capabilities only.
|
|
36
|
+
- `lessons.md` — hot: pending mistakes and the rules derived from them.
|
|
37
|
+
- `memory/README.md` — cold: archive contract for rotated state.
|
|
38
|
+
- `memory/progress/<YYYY-MM>.md` — cold: archived progress entries by month.
|
|
39
|
+
- `memory/features-archive.json` — cold: verified capabilities with evidence.
|
|
40
|
+
- `memory/lessons/<YYYY-MM>.md` — cold: promoted lessons by month.
|
|
41
|
+
- Rotate with `node rotate-state.mjs`; the state gate fails when
|
|
42
|
+
`progress.md` or `lessons.md` exceeds its line budget.
|
|
43
|
+
|
|
44
|
+
## Commands
|
|
45
|
+
|
|
46
|
+
<!-- Fill these in for your project. Codex reads this table before guessing. -->
|
|
47
|
+
|
|
48
|
+
- Setup:
|
|
49
|
+
- Test:
|
|
50
|
+
- Lint:
|
|
51
|
+
- Build:
|
|
52
|
+
- Smoke: `./init.sh`
|
|
53
|
+
- State gate: `node verify-state.mjs`
|
|
54
|
+
- Memory rotate: `node rotate-state.mjs`
|
|
55
|
+
|
|
56
|
+
## Rules
|
|
57
|
+
|
|
58
|
+
- Work on one feature from `feature_list.json` at a time; do not widen scope
|
|
59
|
+
mid-session.
|
|
60
|
+
- If `team/` exists, multi-role work follows `team/workflow.md`: one session
|
|
61
|
+
plays one role (planner, implementer, or evaluator) and `node
|
|
62
|
+
team/verify-team.mjs` must pass alongside the state gate.
|
|
63
|
+
- Keep changes scoped to the requested feature or fix.
|
|
64
|
+
- Update a feature status in `feature_list.json` only after its `verify`
|
|
65
|
+
commands pass.
|
|
66
|
+
- When a task changes behavior, guardrails, packages, scripts, or tests, update
|
|
67
|
+
`feature_list.json` and `progress.md` before finishing — even for small
|
|
68
|
+
tasks. The latest progress entry must list the changed files.
|
|
69
|
+
- Run `node verify-state.mjs` before committing; it mechanically enforces the
|
|
70
|
+
rule above and must pass.
|
|
71
|
+
- When a verify gate, test, or review catches a mistake the agent caused, log
|
|
72
|
+
it in `lessons.md` via `$lessons-harness` before finishing the session. If
|
|
73
|
+
the same rule appears twice, promote it into this file or a verify gate.
|
|
74
|
+
- End every session with a descriptive commit and a `progress.md` entry. The
|
|
75
|
+
commit is the recovery point the next Codex session reverts to if a change
|
|
76
|
+
goes bad.
|
|
77
|
+
- Do not refactor unrelated code.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "F001",
|
|
4
|
+
"title": "Replace me with the first real capability",
|
|
5
|
+
"status": "not_started",
|
|
6
|
+
"acceptance": [
|
|
7
|
+
"User can ...",
|
|
8
|
+
"System rejects ...",
|
|
9
|
+
"Regression check passes ..."
|
|
10
|
+
],
|
|
11
|
+
"verify": [
|
|
12
|
+
"./init.sh"
|
|
13
|
+
],
|
|
14
|
+
"evidence": []
|
|
15
|
+
}
|
|
16
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
cd "$(dirname "$0")"
|
|
5
|
+
|
|
6
|
+
# Keep this script idempotent: a brand-new session runs it first, before any
|
|
7
|
+
# edit. It should set up the environment and run the cheapest smoke test.
|
|
8
|
+
#
|
|
9
|
+
# Replace the lines below with your project's real commands, for example:
|
|
10
|
+
# npm ci && npm test
|
|
11
|
+
# make setup && make smoke
|
|
12
|
+
|
|
13
|
+
echo "init.sh is not configured yet." >&2
|
|
14
|
+
echo "Edit init.sh to run this project's setup and cheapest smoke test." >&2
|
|
15
|
+
exit 1
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Lessons
|
|
2
|
+
|
|
3
|
+
Mistakes this project has learned from, externalized so the next session does
|
|
4
|
+
not repeat them. Log a lesson when a gate or test fails for an agent-caused
|
|
5
|
+
reason, a regression appears, review catches an agent-made defect, or the same
|
|
6
|
+
correction is applied twice. See `$lessons-harness` for the full workflow.
|
|
7
|
+
|
|
8
|
+
Each lesson is one dated `## YYYY-MM-DD - Title` entry with four fields:
|
|
9
|
+
`- Mistake:` what went wrong and where it was observed; `- Root cause:` why it
|
|
10
|
+
happened; `- Rule:` the concrete behavior or check that prevents it next time;
|
|
11
|
+
`- Status: pending` until the rule is promoted.
|
|
12
|
+
|
|
13
|
+
When the same rule appears in two or more lessons, promote it into `AGENTS.md`
|
|
14
|
+
or a mechanical gate, change the line to `- Status: promoted: <where>`, and run
|
|
15
|
+
`node rotate-state.mjs`. Promoted lessons are archived; pending lessons stay
|
|
16
|
+
hot and are read at the start of every session.
|
|
17
|
+
|
|
18
|
+
Promoted lessons: see `memory/lessons/`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Memory Archive
|
|
2
|
+
|
|
3
|
+
Cold storage for archived harness state.
|
|
4
|
+
|
|
5
|
+
Hot files live at the repository root and are read every session:
|
|
6
|
+
|
|
7
|
+
- `progress.md`
|
|
8
|
+
- `feature_list.json`
|
|
9
|
+
- `lessons.md`
|
|
10
|
+
|
|
11
|
+
Rotate hot state with `node rotate-state.mjs` when the hot files approach their
|
|
12
|
+
budget or when verified features / promoted lessons should move out of the hot
|
|
13
|
+
set.
|
|
14
|
+
|
|
15
|
+
Cold archive layout:
|
|
16
|
+
|
|
17
|
+
- `memory/progress/<YYYY-MM>.md`
|
|
18
|
+
- `memory/features-archive.json`
|
|
19
|
+
- `memory/lessons/<YYYY-MM>.md`
|
|
20
|
+
|
|
21
|
+
Do not put live task state here. This file is the contract for the cold archive
|
|
22
|
+
layout and recovery path.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Progress
|
|
2
|
+
|
|
3
|
+
Keep entries short and recoverable. Prefer file paths, command names, failing
|
|
4
|
+
test names, and artifact paths over vague prose. Newest entry goes last.
|
|
5
|
+
|
|
6
|
+
## YYYY-MM-DD - Harness bootstrap
|
|
7
|
+
|
|
8
|
+
### Context
|
|
9
|
+
|
|
10
|
+
- Task: Bootstrap the repository harness.
|
|
11
|
+
- Current branch:
|
|
12
|
+
- Relevant files: `AGENTS.md`, `progress.md`, `feature_list.json`,
|
|
13
|
+
`memory/README.md`, `init.sh`, `verify-state.mjs`, `rotate-state.mjs`.
|
|
14
|
+
|
|
15
|
+
### Done
|
|
16
|
+
|
|
17
|
+
- Installed the minimal harness scaffold.
|
|
18
|
+
|
|
19
|
+
### Verification
|
|
20
|
+
|
|
21
|
+
- Command: `./init.sh`
|
|
22
|
+
- Result: <!-- record the real result; do not mark pass without running it -->
|
|
23
|
+
- Command: `node verify-state.mjs`
|
|
24
|
+
- Result: <!-- record the real result -->
|
|
25
|
+
|
|
26
|
+
### Open Issues
|
|
27
|
+
|
|
28
|
+
- `init.sh` still needs the project's real setup and smoke commands.
|
|
29
|
+
|
|
30
|
+
### Next
|
|
31
|
+
|
|
32
|
+
- Fill in the Commands section of `AGENTS.md`.
|
|
33
|
+
- Replace the placeholder feature in `feature_list.json` with real capabilities.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Rotates harness memory so the hot state files stay small enough for an
|
|
3
|
+
// agent to read at the start of every session.
|
|
4
|
+
//
|
|
5
|
+
// - progress.md keeps the latest KEEP_ENTRIES entries; older entries move to
|
|
6
|
+
// memory/progress/<YYYY-MM>.md grouped by entry month.
|
|
7
|
+
// - feature_list.json keeps non-verified features; verified features move to
|
|
8
|
+
// memory/features-archive.json with their evidence.
|
|
9
|
+
// - lessons.md keeps pending lessons; promoted lessons move to
|
|
10
|
+
// memory/lessons/<YYYY-MM>.md grouped by entry month.
|
|
11
|
+
//
|
|
12
|
+
// Run: node rotate-state.mjs [root]
|
|
13
|
+
// The state gate (verify-state.mjs) reminds you when progress.md grows past
|
|
14
|
+
// its line budget.
|
|
15
|
+
|
|
16
|
+
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
|
|
20
|
+
const ROOT = process.argv[2]
|
|
21
|
+
? path.resolve(process.argv[2])
|
|
22
|
+
: path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const KEEP_ENTRIES = 5;
|
|
24
|
+
|
|
25
|
+
function splitEntries(progress) {
|
|
26
|
+
const lines = progress.split("\n");
|
|
27
|
+
const starts = [];
|
|
28
|
+
lines.forEach((line, index) => {
|
|
29
|
+
if (line.startsWith("## ")) {
|
|
30
|
+
starts.push(index);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const headerEnd = starts.length > 0 ? starts[0] : lines.length;
|
|
35
|
+
const header = lines.slice(0, headerEnd).join("\n").trimEnd();
|
|
36
|
+
const entries = starts.map((start, n) =>
|
|
37
|
+
lines.slice(start, starts[n + 1] ?? lines.length).join("\n").trimEnd()
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return { header, entries };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function entryMonth(entry) {
|
|
44
|
+
const match = entry.match(/^## (\d{4}-\d{2})/);
|
|
45
|
+
return match ? match[1] : "undated";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function archiveByMonth(directory, entries) {
|
|
49
|
+
await mkdir(directory, { recursive: true });
|
|
50
|
+
|
|
51
|
+
const byMonth = new Map();
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const month = entryMonth(entry);
|
|
54
|
+
byMonth.set(month, [...(byMonth.get(month) ?? []), entry]);
|
|
55
|
+
}
|
|
56
|
+
for (const [month, monthEntries] of byMonth) {
|
|
57
|
+
await appendFile(
|
|
58
|
+
path.join(directory, `${month}.md`),
|
|
59
|
+
`${monthEntries.join("\n\n")}\n\n`,
|
|
60
|
+
"utf8"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function writeHotFile(filePath, header, pointer, entries) {
|
|
66
|
+
const headerWithPointer = header.includes(pointer) ? header : `${header}\n\n${pointer}`;
|
|
67
|
+
await writeFile(filePath, `${[headerWithPointer, ...entries].join("\n\n")}\n`, "utf8");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const progressPath = path.join(ROOT, "progress.md");
|
|
71
|
+
const { header, entries } = splitEntries(await readFile(progressPath, "utf8"));
|
|
72
|
+
const archivedEntries = entries.slice(0, Math.max(0, entries.length - KEEP_ENTRIES));
|
|
73
|
+
const keptEntries = entries.slice(-KEEP_ENTRIES);
|
|
74
|
+
|
|
75
|
+
if (archivedEntries.length > 0) {
|
|
76
|
+
await archiveByMonth(path.join(ROOT, "memory", "progress"), archivedEntries);
|
|
77
|
+
await writeHotFile(
|
|
78
|
+
progressPath,
|
|
79
|
+
header,
|
|
80
|
+
"Older entries: see `memory/progress/`.",
|
|
81
|
+
keptEntries
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let archivedLessons = 0;
|
|
86
|
+
const lessonsPath = path.join(ROOT, "lessons.md");
|
|
87
|
+
try {
|
|
88
|
+
const { header: lessonsHeader, entries: lessonsEntries } = splitEntries(await readFile(lessonsPath, "utf8"));
|
|
89
|
+
const promoted = lessonsEntries.filter((entry) => /\n- Status: promoted:/.test(entry));
|
|
90
|
+
const pending = lessonsEntries.filter((entry) => !/\n- Status: promoted:/.test(entry));
|
|
91
|
+
|
|
92
|
+
if (promoted.length > 0) {
|
|
93
|
+
await archiveByMonth(path.join(ROOT, "memory", "lessons"), promoted);
|
|
94
|
+
await writeHotFile(
|
|
95
|
+
lessonsPath,
|
|
96
|
+
lessonsHeader,
|
|
97
|
+
"Promoted lessons: see `memory/lessons/`.",
|
|
98
|
+
pending
|
|
99
|
+
);
|
|
100
|
+
archivedLessons = promoted.length;
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (error.code !== "ENOENT") {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const featuresPath = path.join(ROOT, "feature_list.json");
|
|
109
|
+
const features = JSON.parse(await readFile(featuresPath, "utf8"));
|
|
110
|
+
const verified = features.filter((feature) => feature.status === "verified");
|
|
111
|
+
const active = features.filter((feature) => feature.status !== "verified");
|
|
112
|
+
|
|
113
|
+
if (verified.length > 0) {
|
|
114
|
+
const archivePath = path.join(ROOT, "memory", "features-archive.json");
|
|
115
|
+
await mkdir(path.join(ROOT, "memory"), { recursive: true });
|
|
116
|
+
|
|
117
|
+
let archive = [];
|
|
118
|
+
try {
|
|
119
|
+
archive = JSON.parse(await readFile(archivePath, "utf8"));
|
|
120
|
+
} catch {
|
|
121
|
+
// first rotation: archive file does not exist yet
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await writeFile(archivePath, `${JSON.stringify([...archive, ...verified], null, 2)}\n`, "utf8");
|
|
125
|
+
await writeFile(featuresPath, `${JSON.stringify(active, null, 2)}\n`, "utf8");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log(
|
|
129
|
+
`Archived ${archivedEntries.length} progress entries, ${verified.length} verified features, ` +
|
|
130
|
+
`and ${archivedLessons} promoted lessons to memory/.`
|
|
131
|
+
);
|