@jaybeeuu/agent-cortex 2.7.0 → 2.9.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 +412 -0
- package/README.md +87 -8
- package/agents/README.md +4 -4
- package/agents/guppi/agent.md +162 -0
- package/agents/guppi/claude/frontmatter.json +6 -0
- package/agents/guppi/pi/frontmatter.json +6 -0
- package/agents/plan/agent.md +6 -0
- package/agents/ralph/agent.md +17 -16
- package/agents/ralph/claude/wake.md +4 -4
- package/agents/ralph/pi/wake.md +15 -20
- package/agents/ralph-plan/agent.md +6 -0
- package/bin/agent-cortex.mjs +20 -1
- package/bin/installers/claude.mjs +1 -20
- package/bin/installers/pi.mjs +8 -2
- package/extensions/interrupt-bookmark/README.md +129 -0
- package/extensions/interrupt-bookmark/index.test.ts +717 -0
- package/extensions/interrupt-bookmark/index.ts +354 -0
- package/extensions/interrupt-bookmark/package.json +20 -0
- package/extensions/post-merge-watch/README.md +133 -0
- package/extensions/post-merge-watch/index.test.ts +247 -0
- package/extensions/post-merge-watch/index.ts +123 -0
- package/extensions/post-merge-watch/package.json +16 -0
- package/extensions/post-merge-watch/watch.test.ts +469 -0
- package/extensions/post-merge-watch/watch.ts +431 -0
- package/extensions/session-clear/README.md +74 -0
- package/extensions/session-clear/index.test.ts +524 -0
- package/extensions/session-clear/index.ts +159 -0
- package/extensions/session-clear/package.json +16 -0
- package/extensions/skill-stats/README.md +84 -3
- package/extensions/skill-stats/index.ts +62 -3
- package/extensions/skill-stats/package.json +1 -1
- package/extensions/skill-stats/rollup.test.ts +643 -0
- package/extensions/skill-stats/rollup.ts +415 -0
- package/extensions/skill-stats/timeline.ts +101 -0
- package/lib/cli.mjs +42 -1
- package/lib/self-update.mjs +553 -0
- package/package.json +1 -1
- package/scripts/lib/manifest.mjs +29 -0
- package/skills/engineering/implement-task/SKILL.md +124 -0
- package/skills/engineering/tdd/SKILL.md +2 -0
- package/skills/planning/create-task/REFERENCE.md +15 -6
- package/skills/planning/create-task/SKILL.md +1 -1
- package/skills/planning/create-task/pipeline.json +8 -0
- package/skills/planning/create-task/scripts/create-chores.mjs +27 -18
- package/skills/planning/create-task/templates/code.md +8 -3
- package/skills/planning/create-task/templates/document.md +8 -3
- package/skills/planning/create-task/templates/fix.md +8 -3
- package/skills/planning/create-task/templates/housekeeping.md +8 -4
- package/skills/planning/create-task/templates/post-merge.md +67 -0
- package/skills/planning/create-task/templates/review.md +8 -3
- package/skills/planning/create-task/templates/verify.md +8 -3
- package/skills/productivity/bd-tool/SKILL.md +55 -0
- package/skills/review/review-defects/EXAMPLES.md +198 -0
- package/skills/review/review-defects/SKILL.md +121 -0
- package/skills/review/review-report/EXAMPLES.md +114 -0
- package/skills/review/review-report/SKILL.md +138 -0
- package/skills/review/review-report/scripts/report.mjs +1032 -0
- package/skills/style/style-tests/EXAMPLES.md +30 -0
- package/skills/style/style-tests/SKILL.md +10 -6
- package/skills/workflow/hitl-queue/SKILL.md +134 -0
- package/skills/workflow/hitl-queue/scripts/queue.mjs +626 -0
- package/skills/workflow/plan/SKILL.md +27 -3
- package/skills/workflow/prioritise-work/CHALLENGE.md +139 -0
- package/skills/workflow/prioritise-work/SKILL.md +150 -0
- package/skills/workflow/prioritise-work/scripts/challenge.mjs +505 -0
- package/skills/workflow/prioritise-work/scripts/strategy.mjs +566 -0
- package/skills/workflow/prioritise-work/templates/strategy.md +61 -0
- package/skills/workflow/ralph/REFERENCE.md +124 -27
- package/skills/workflow/ralph/SKILL.md +24 -15
- package/skills/workflow/ralph/scripts/post-merge-check.mjs +651 -0
- package/skills/workflow/run-pipeline-stage/SKILL.md +37 -22
- package/skills/workflow/run-pipeline-stage/playbooks/code.md +14 -8
- package/skills/workflow/run-pipeline-stage/playbooks/document.md +2 -2
- package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -2
- package/skills/workflow/run-pipeline-stage/playbooks/housekeeping.md +1 -1
- package/skills/workflow/run-pipeline-stage/playbooks/post-merge.md +54 -0
- package/skills/workflow/run-pipeline-stage/playbooks/review.md +37 -3
- package/skills/workflow/run-pipeline-stage/playbooks/verify.md +2 -2
- package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +55 -11
- package/skills/workflow/run-pipeline-stage/scripts/recover-brief.mjs +805 -0
- package/skills/workflow/run-pipeline-stage/scripts/trail-entry.mjs +702 -0
- package/skills/workflow/score-bead/FORMAT.md +73 -0
- package/skills/workflow/score-bead/SKILL.md +112 -0
- package/skills/workflow/score-bead/scripts/rice.mjs +664 -0
- package/skills/workflow/using-agent-skills/SKILL.md +21 -8
- package/token-map.README.md +27 -0
- package/token-map.json +16 -4
|
@@ -434,6 +434,36 @@ for (const item of cart.items) {
|
|
|
434
434
|
expect(cart.items.map((item) => item.price)).toStrictEqual([10, 20, 30]);
|
|
435
435
|
```
|
|
436
436
|
|
|
437
|
+
### A test name is a claim
|
|
438
|
+
|
|
439
|
+
The name says what the test proves. Read it as a list of assertions and check that each one
|
|
440
|
+
appears in the body. A clause with no assertion is a requirement the suite never enforces, so the
|
|
441
|
+
test stays green while the behaviour breaks.
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
// ❌ Instead — the name claims one notice; the body only claims that something exists.
|
|
445
|
+
// Remove the notice and this test still passes, because a list is always defined.
|
|
446
|
+
it("sends one notice", async () => {
|
|
447
|
+
await publishAll(recipients);
|
|
448
|
+
|
|
449
|
+
expect(await notices.list()).toBeDefined();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// ✅ Write — the count in the name is asserted, so two notices and no notices both fail
|
|
453
|
+
it("sends one notice", async () => {
|
|
454
|
+
await publishAll(recipients);
|
|
455
|
+
|
|
456
|
+
expect(await notices.list()).toHaveLength(1);
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
A state in the name works the same way — "returns the cached user" needs an assertion that the
|
|
461
|
+
returned user came from the cache, not that a user came back — and a "not" needs an assertion of
|
|
462
|
+
the absence, such as a call count of zero.
|
|
463
|
+
|
|
464
|
+
The *Workflow* mutation check catches this at run time: disable the behaviour and the bad form
|
|
465
|
+
above stays green, while the good form goes red.
|
|
466
|
+
|
|
437
467
|
## Determinism and async
|
|
438
468
|
|
|
439
469
|
```ts
|
|
@@ -25,6 +25,7 @@ description: Defines test-writing conventions — assertion strategy, mock disci
|
|
|
25
25
|
- **Integration and e2e exercise real services.** Run the genuine collaborator — Postgres, Redis, a queue, object storage via TestContainers or LocalStack — never a fake that drifts from the real contract. Reserve e2e for a small number of smoke tests proving the system hangs together.
|
|
26
26
|
- **No more tests than needed.** Every test earns its cost by pinpointing exactly where a failure lies. A test that cannot localise a fault adds maintenance weight without signal.
|
|
27
27
|
- **One behaviour per test.** A test should fail for exactly one reason; several unrelated assertions turn a failure into a debugging exercise.
|
|
28
|
+
- **A test's name is a claim, and every clause of it is an assertion.** A count in the name — "one notice", "both callers", "no retries" — asserts that count; a state in the name asserts that state; a "not" in the name asserts the absence. A name that outruns its assertions states a requirement the test never proves, so the test cannot fail for the reason its name promises. See _Red Flags_, and the "one notice" pair under _A test name is a claim_ in `EXAMPLES.md`.
|
|
28
29
|
- **Test code is production code.** Linted, typechecked, properly typed — no `any`, no unsafe casts, no shortcuts in constructing data. Tolerate WETness where it leaves tests more descriptive.
|
|
29
30
|
- **All setup and assertion data is visible inline.** Show exactly and only the values that explain the case; a helper with sensible defaults keeps it terse.
|
|
30
31
|
- **Deterministic and performant.** A failing or flaky test is investigated now. Deferring is acceptable only against a top-priority bead.
|
|
@@ -71,7 +72,9 @@ Worked examples for each rule are in `EXAMPLES.md` under _Test data_.
|
|
|
71
72
|
|
|
72
73
|
5. **Write targeted assertions.** Prefer `toMatchObject` over asserting every property. Multiple assertions are fine when they all verify the same behaviour. Avoid asserting call counts when asserting call arguments already covers the behaviour. Assert behaviour the file participates in, never its static contents.
|
|
73
74
|
|
|
74
|
-
6. **
|
|
75
|
+
6. **Run the mutation check.** Before you finish, disable or revert each behaviour a test claims, then run the suite. Every test named for that behaviour must fail. A named test that still passes proves nothing about its name: it is the _Red Flags_ row on empty implementations, applied to the whole name. Restore the behaviour and confirm the suite is green again.
|
|
76
|
+
|
|
77
|
+
7. **Review against the checklist below.** Read the test as if you are seeing the codebase for the first time.
|
|
75
78
|
|
|
76
79
|
## Red Flags
|
|
77
80
|
|
|
@@ -80,7 +83,8 @@ Worked examples for each rule are in `EXAMPLES.md` under _Test data_.
|
|
|
80
83
|
| Asserting static file content — an expected config/markdown/terraform string, or a snapshot of static content | Assert the behaviour the file participates in: data inserted into a template, a header compiled correctly, a deployed service ready to serve traffic |
|
|
81
84
|
| Shared mutable top-level fixture reused across tests | Build fresh data per test via a factory; a module-scope constant only when genuinely immutable and read-only |
|
|
82
85
|
| Repeated full literals for the same shape | A small configurable factory taking partial overrides with sensible defaults |
|
|
83
|
-
| A test with no assertion, or one that
|
|
86
|
+
| A test with no assertion, or one that passes against an empty implementation (`expect(result).toBeDefined()`) | Assert the observable contract — a specific value the code must produce |
|
|
87
|
+
| A test name whose claim no assertion mentions — "one notice" proven only by `toBeDefined()`, a count proven by truthiness | Assert every clause of the name: the count (`toHaveLength(1)`), the state, the absence |
|
|
84
88
|
| Computing the expected value with the implementation's own logic | Hard-code the expected value from a known-good case; the test must not share the implementation's bug |
|
|
85
89
|
| Mocking implementation details or internal module structure | Mock the genuine external boundary and test through the public interface |
|
|
86
90
|
| An "integration" test that mocks the collaborator it is meant to integrate with | Run the real collaborator (TestContainers/LocalStack); a fake drifts from the real contract |
|
|
@@ -115,9 +119,8 @@ Worked examples for each rule are in `EXAMPLES.md` under _Test data_.
|
|
|
115
119
|
|
|
116
120
|
## Examples
|
|
117
121
|
|
|
118
|
-
The full `❌ Instead` / `✅ Write` catalogue lives in `EXAMPLES.md
|
|
119
|
-
|
|
120
|
-
naming, determinism and async, isolation, and content assertions. Headline pairs:
|
|
122
|
+
The full `❌ Instead` / `✅ Write` catalogue lives in `EXAMPLES.md` — including _A test name is a
|
|
123
|
+
claim_, with the "one notice" pair. Headline pairs:
|
|
121
124
|
|
|
122
125
|
| Instead of… | Write… |
|
|
123
126
|
|---|---|
|
|
@@ -131,7 +134,8 @@ naming, determinism and async, isolation, and content assertions. Headline pairs
|
|
|
131
134
|
- [ ] Test verifies behaviour, not implementation structure
|
|
132
135
|
- [ ] Integration tests exercise the real collaborator — no mocking the engine you are integrating with
|
|
133
136
|
- [ ] E2E smoke tests prove wiring, migrations, and the journey — not business rules covered lower down
|
|
134
|
-
- [ ] Each test fails for exactly one reason, and its name states
|
|
137
|
+
- [ ] Each test fails for exactly one reason, and its name states only behaviour an assertion proves — count, state, and absence included
|
|
138
|
+
- [ ] Mutation check run: each claimed behaviour was disabled, its named tests failed, and the suite is green again
|
|
135
139
|
- [ ] No mocking of internal module details — only public interfaces
|
|
136
140
|
- [ ] No `before`/`after` hooks for shared test state (infrastructure setup only)
|
|
137
141
|
- [ ] Assertions are targeted — no over-asserting, no tautologies, no assertion-free tests
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hitl-queue
|
|
3
|
+
description: Ranks the open execution:hitl beads into one list ordered by RICE, transitively blocked dependents and work in progress, and prints what each answer unblocks. Use when deciding which human decision to answer next, when a planning session starts, or when asked "what needs my decision", "show the queue" or "what should I answer first".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# HITL Queue
|
|
7
|
+
|
|
8
|
+
Owns one output: **the ranked list of beads waiting for a human answer**. Each row carries its own arithmetic, so the owner can check *why* one decision outranks another instead of trusting a number.
|
|
9
|
+
|
|
10
|
+
A queue is not a priority. The RICE score is `score-bead`'s judgement, the band it implies is reviewed there, and this skill only orders beads by a number that already exists. Where no score exists, the queue says so and ranks nothing: inventing an order would hide the gap a person has to fill.
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
- A planning session starts and the owner needs to know which decision comes first.
|
|
15
|
+
- "What needs my decision?", "show the queue", "what should I answer first?".
|
|
16
|
+
- Before dispatching work from a backlog of HITL beads: the answer unblocks the work, so the order of answers is the order of the work.
|
|
17
|
+
- A bead was scored or re-scored and the order should follow the new number.
|
|
18
|
+
|
|
19
|
+
## When NOT to use
|
|
20
|
+
|
|
21
|
+
- Judging one bead's components — use `score-bead`. This skill reads a score, it never makes one.
|
|
22
|
+
- Writing or bumping the rubric the score rests on — use `prioritise-work`.
|
|
23
|
+
- Choosing what to *build* next with an agent — `ralph` drains `execution:afk` beads, and ideas are ranked by `flesh-out-idea`.
|
|
24
|
+
- Recording a new idea — use `record-idea`.
|
|
25
|
+
|
|
26
|
+
## The formula
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
total = rice × (1 + ln(1 + dependents)) × (in progress ? 1.5 : 1)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| Term | Meaning |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `rice` | The stored `score` from the bead's `rice` metadata, written by `score-bead`. Never recomputed here. |
|
|
35
|
+
| `dependents` | Distinct beads that wait on this answer, **transitively**. |
|
|
36
|
+
| `1.5` | Work in progress outranks equal work not started, so the queue drains WIP first. |
|
|
37
|
+
|
|
38
|
+
The dependent count is the load-bearing term. A bead blocking A, which blocks B, which blocks C, unblocks **three**. The walk follows `bd dep list <id> --direction up` from bead to bead, and collects **beads, not paths**: when the graph reconverges (a diamond — one bead reached by two routes), it is counted once. Counting paths would measure the shape of the graph instead of the work an answer releases.
|
|
39
|
+
|
|
40
|
+
Two edges of the walk are deliberate:
|
|
41
|
+
|
|
42
|
+
- **Only `blocks` edges count.** A related or duplicate edge is not something anyone waits on.
|
|
43
|
+
- **The walk passes through every bead; it counts only live ones.** A closed bead is still a link in the chain, so the walk continues past it, but finished work cannot be unblocked, so a closed dependent is not counted.
|
|
44
|
+
|
|
45
|
+
`1 + ln(1 + n)` is logarithmic on purpose: unblocking thirty chores must not drown the list under one row. Zero dependents scores `1`, so a bead that unblocks nothing is not penalised — it is simply not lifted.
|
|
46
|
+
|
|
47
|
+
## The report
|
|
48
|
+
|
|
49
|
+
One flat list, no sections, ranked first and unscored last:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
HITL decision queue · 2 ranked, 2 unscored · strategy v2
|
|
53
|
+
total = rice × (1 + ln(1 + dependents)) × 1.5 in-progress · ties break on rice, then id · unscored last
|
|
54
|
+
excluded: 3 kind:idea beads (--include-ideas ranks them)
|
|
55
|
+
|
|
56
|
+
1 bd-7 10.0 rice 4.2 = R4 · I3 · C0.7 · E2 ×2.39 dependents(3) ×1.0
|
|
57
|
+
Ship the queue — unblocks bd-8, bd-9, bd-10
|
|
58
|
+
2 bd-2 6.3 rice 4.2 = R4 · I3 · C0.7 · E2 ×1.00 dependents(0) ×1.5 in-progress
|
|
59
|
+
Decide the API shape — unblocks nothing
|
|
60
|
+
- bd-4 — unscored — no rice metadata (score it with score-bead)
|
|
61
|
+
Decide the vendor — unblocks nothing
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Every row carries its rank, id, total, the four components the score was computed from, both multipliers, the title, and one clause naming what the answer unblocks. An unscored row keeps its place at the end of the same list with the reason: no `rice` metadata, no score inside a `rice` record, or scored against an older strategy version (that last one is ranked and marked `scored at strategy v1, current v2`).
|
|
65
|
+
|
|
66
|
+
`--json` prints the same answer with every derived field, for a caller that needs to act on it.
|
|
67
|
+
|
|
68
|
+
## Ordering rules
|
|
69
|
+
|
|
70
|
+
- **Ranked by total, descending.** The total is rounded to one decimal *before* ranking, so the number a reader sees is the number the order was decided by.
|
|
71
|
+
- **Ties break on rice, then id.** `ln` flattens, so different dependent counts can reach the same one-decimal total; a fixed tie-break means two runs over one backlog print byte-identical output.
|
|
72
|
+
- **Unscored beads never earn a rank.** They are listed, not placed, and never compared by title or by priority.
|
|
73
|
+
|
|
74
|
+
## Workflow
|
|
75
|
+
|
|
76
|
+
1. **Check the strategy is readable.** The queue compares each score's `strategyVersion` against the file to mark stale scores. A missing or invalid strategy does not stop the run — the scores are already on the beads — but the header then reports `strategy unknown` and no staleness.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
node <skill-scripts>/../../prioritise-work/scripts/strategy.mjs validate
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. **Run the queue.** This is the hand-run form: no planner, no agent, one command.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node <skill-scripts>/queue.mjs queue
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. **Report it as printed**, then name the top item plainly: id, title, and what answering it unblocks. Do not group by priority, re-sort, or drop the unscored rows — the flat list is the answer.
|
|
89
|
+
|
|
90
|
+
4. **Score what is unscored, one bead at a time.** Load `score-bead`, judge the four components against the strategy, and record the score. Re-run the queue; the bead takes its place.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
node <skill-scripts>/queue.mjs queue --json # the same answer, structured
|
|
94
|
+
node <skill-scripts>/queue.mjs queue --file <path> --include-ideas
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Option | Effect |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `--file <path>` | Strategy file. Default `.agent-cortex/working-docs/strategy.md`, relative to the repository root. |
|
|
100
|
+
| `--include-ideas` | Rank `kind:idea` beads too. They are excluded by default — see below. |
|
|
101
|
+
| `--cwd <dir>` | Directory the strategy path and `bd` resolve from. |
|
|
102
|
+
| `--json` | Print the report as JSON. |
|
|
103
|
+
|
|
104
|
+
`BD_PATH` pins the `bd` binary. Exit `0` means the queue was built, including a run that ranked nothing. Exit `1` means a `bd` call failed, and exit `2` means a malformed argument. The script makes no writes: the tracker calls are `bd list` and `bd dep list`, nothing else.
|
|
105
|
+
|
|
106
|
+
## What the queue leaves out
|
|
107
|
+
|
|
108
|
+
- **Ideas, by default.** `kind:idea` beads are HITL by convention but deliberately unshaped: a RICE score on an idea measures a guess about a guess, and the idea backlog is ranked by `flesh-out-idea` instead. An idea that outranks a ripe decision would send the owner into an interview they did not choose. The count is printed so nothing is dropped silently; `--include-ideas` ranks them when the backlog is what the owner is working.
|
|
109
|
+
- **Deferred beads.** A deferral is itself an answer, so a parked bead stays out of the queue until the owner lifts it (`bd update <id> --status open`). The count is printed.
|
|
110
|
+
- **Closed beads.** Finished work waits on nothing.
|
|
111
|
+
|
|
112
|
+
## Red Flags
|
|
113
|
+
|
|
114
|
+
- Red flag: scoring a bead inside this skill, so the queue's order rests on an unreviewed number.
|
|
115
|
+
- Red flag: ranking an unscored bead by its priority or its title, so the list looks complete and hides the gap.
|
|
116
|
+
- Red flag: counting dependency paths instead of distinct beads, so a diamond inflates one row above its real value.
|
|
117
|
+
- Red flag: re-sorting or grouping the flat list before reporting it, so the order the owner reads is not the order that was computed.
|
|
118
|
+
- Red flag: excluding ideas without printing how many were excluded.
|
|
119
|
+
|
|
120
|
+
## Verification checklist
|
|
121
|
+
|
|
122
|
+
- [ ] The report is one flat list: ranked rows first, unscored rows last, no sections.
|
|
123
|
+
- [ ] Each row shows the rank, id, total, the four components, both multipliers, the title and what the answer unblocks.
|
|
124
|
+
- [ ] A bead blocking three others ranks above an equal bead blocking none; an in-progress bead ranks above an equal not-started one.
|
|
125
|
+
- [ ] With no scores, the header says nothing can be ranked and every candidate is listed unscored with a reason.
|
|
126
|
+
- [ ] Two identical runs printed byte-identical output.
|
|
127
|
+
- [ ] The excluded idea and deferred counts were reported, or the header said there were none.
|
|
128
|
+
|
|
129
|
+
## See Also
|
|
130
|
+
|
|
131
|
+
- [score-bead](../score-bead/SKILL.md) — owns the `rice` record this queue reads, and the band proposal.
|
|
132
|
+
- [prioritise-work](../prioritise-work/SKILL.md) — owns the strategy file and its version.
|
|
133
|
+
- [bd-tool](../../productivity/bd-tool/SKILL.md) — the tracker commands, and where operational state lives.
|
|
134
|
+
- [hitl-collab](../hitl-collab/SKILL.md) — the handoff document for a decision that needs more than an answer.
|