@pikku/skills 0.12.49 → 0.12.50
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/dist/skills.gen.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-addon/references/openapi.md +1 -1
- package/skills/pikku-architect/SKILL.md +64 -55
- package/skills/pikku-architect/references/plan-defects.md +14 -14
- package/skills/pikku-build/SKILL.md +17 -16
- package/skills/pikku-build/references/app.md +86 -122
- package/skills/pikku-build/references/design.md +13 -13
- package/skills/pikku-build/references/multi-app.md +1 -1
- package/skills/pikku-build/references/platform.md +7 -7
- package/skills/pikku-build/references/quick.md +5 -5
- package/skills/pikku-build/references/scenarios.md +19 -19
- package/skills/pikku-build/references/ship.md +8 -8
- package/skills/pikku-changes/SKILL.md +73 -27
- package/skills/pikku-knowledge/SKILL.md +41 -81
|
@@ -4,7 +4,7 @@ A scenario is a user journey run as one of your personas, over the real transpor
|
|
|
4
4
|
persona's session. It is the only kind of test worth writing here, because a passing one proves the
|
|
5
5
|
app works the way a signed-in person experiences it.
|
|
6
6
|
|
|
7
|
-
The traps below all cost a real
|
|
7
|
+
The traps below all cost a real changeset a red run, and most of them are invisible on the run that
|
|
8
8
|
introduces them. Read the section that matches what you are writing.
|
|
9
9
|
|
|
10
10
|
1. [The shape of a scenario](#the-shape-of-a-scenario)
|
|
@@ -20,8 +20,8 @@ introduces them. Read the section that matches what you are writing.
|
|
|
20
20
|
|
|
21
21
|
## The shape of a scenario
|
|
22
22
|
|
|
23
|
-
Three ship in `packages/functions/test/scenarios/` — keep them green — and every
|
|
24
|
-
|
|
23
|
+
Three ship in `packages/functions/test/scenarios/` — keep them green — and every scenario a
|
|
24
|
+
changeset's plan names becomes one more.
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
27
|
import { pikkuScenario } from '#pikku/scenarios'
|
|
@@ -83,7 +83,7 @@ how the value stays inspectable when the step's output is what the scenario retu
|
|
|
83
83
|
**Only `const`/`let`, `if`/`else`, `switch`, `for..of`, `return`, `throw` and workflow calls
|
|
84
84
|
survive.** A counting `for` is refused by PKU679, and so is a `for..of` whose iterable is written
|
|
85
85
|
inline — it must be a named identifier or a field (`data.items`). Bind the seat numbers, the ids,
|
|
86
|
-
the rows to a `const` above the loop and iterate that. One
|
|
86
|
+
the rows to a `const` above the loop and iterate that. One changeset here lost a codegen round to
|
|
87
87
|
each half of that rule, because the first half does not imply the second.
|
|
88
88
|
|
|
89
89
|
**Write each scenario's setup out in full rather than sharing a local helper.** A helper holding
|
|
@@ -137,7 +137,7 @@ one that archives a product unarchives it, the one that cancels a plan restarts
|
|
|
137
137
|
second run starts where its first one stopped.
|
|
138
138
|
|
|
139
139
|
**Run the suite twice and require the second run green.** A suite that only passes on a fresh
|
|
140
|
-
database is a suite that passes once. Two corollaries, both of which cost a
|
|
140
|
+
database is a suite that passes once. Two corollaries, both of which cost a changeset a red run:
|
|
141
141
|
|
|
142
142
|
- **Name nothing a setup step might already own.** `setsUpHerCompany` returns the company that actor
|
|
143
143
|
already has rather than renaming it, so a later step passed the literal name it had asked for and
|
|
@@ -160,11 +160,11 @@ when a sweep surprises you, the next rule in the calendar is the first place to
|
|
|
160
160
|
|
|
161
161
|
## Steps rot as the app grows
|
|
162
162
|
|
|
163
|
-
A step is shared, so it is the one thing in the suite that a
|
|
163
|
+
A step is shared, so it is the one thing in the suite that a changeset which never mentions it can
|
|
164
164
|
break. Whatever a step selects by, ask what ELSE will match it after the suite has run a hundred
|
|
165
165
|
times.
|
|
166
166
|
|
|
167
|
-
**Drive a new step from both sides in the
|
|
167
|
+
**Drive a new step from both sides in the changeset that adds it.** A step is only as proven as its
|
|
168
168
|
best-exercised branch: one here read the wrong field off a raw invocation (`attempt.data`; the
|
|
169
169
|
payload is `attempt.body`), so its found-case could never pass — invisible for as long as every
|
|
170
170
|
caller asked for ABSENCE.
|
|
@@ -175,9 +175,9 @@ moment a second function produces X: a renewal job that raised invoices broke th
|
|
|
175
175
|
scenarios that had been green for months.
|
|
176
176
|
|
|
177
177
|
**A selector on IDENTITY alone rots the same way once rows gain a lifecycle.** One reused the first
|
|
178
|
-
licence assigned to an email regardless of its state, which was correct until a new
|
|
178
|
+
licence assigned to an email regardless of its state, which was correct until a new changeset's
|
|
179
179
|
refusal scenarios left that actor holding cancelled ones — it then handed back a dead licence, read
|
|
180
|
-
as success, and failed a scenario two
|
|
180
|
+
as success, and failed a scenario two changesets older at a step that needed a live one.
|
|
181
181
|
|
|
182
182
|
**A step's input is a recorded contract, and it does not take a version.** Widening one — an extra
|
|
183
183
|
optional field so a step can name a particular row — trips PKU861 exactly like a function's does,
|
|
@@ -218,10 +218,10 @@ Both are screen defects before they are test defects: a field whose label change
|
|
|
218
218
|
and a list whose rows are indistinguishable to anyone on the phone to support.
|
|
219
219
|
|
|
220
220
|
**A route nested under an existing screen is unreachable until its parent renders an `Outlet`.** A
|
|
221
|
-
|
|
221
|
+
changeset added `/app/academy/$slug` under an `/app/academy` that already had a component of its
|
|
222
222
|
own; the parent swallowed the child, so the editor's URL rendered the list — every link, every route
|
|
223
223
|
file and every type check looked right, and the only thing that noticed was a browser scenario that
|
|
224
|
-
OPENED the child path and found the parent's controls on screen. When a
|
|
224
|
+
OPENED the child path and found the parent's controls on screen. When a changeset deepens a path an
|
|
225
225
|
earlier one already owns, split the parent into a layout (`Outlet`) and an `index` route in the same
|
|
226
226
|
change, and make one scenario open the child by path rather than reach it by clicking.
|
|
227
227
|
|
|
@@ -248,9 +248,9 @@ environment's `appUrls` map, so there is no second environment to run.
|
|
|
248
248
|
browser pass needs the environment's `appUrl` and a browser driver installed — without them the run
|
|
249
249
|
fails fast rather than half-running.
|
|
250
250
|
|
|
251
|
-
**Run the whole suite, not the
|
|
251
|
+
**Run the whole suite, not the changeset's own scenarios.** The changeset's scenarios are the ones
|
|
252
252
|
you wrote to pass; the regression lives in someone else's. Tightening what "archived" means is a
|
|
253
|
-
one-function change that reads as local and quietly breaks the
|
|
253
|
+
one-function change that reads as local and quietly breaks the first changeset's scenario nobody re-ran.
|
|
254
254
|
|
|
255
255
|
**Restart the server after adding a function.** Hot reload does not register a new RPC and does not
|
|
256
256
|
re-run `afterStart`, so a fresh function answers 404 and anything provisioned at boot is missing —
|
|
@@ -272,9 +272,9 @@ That writes `coverage/scenario-coverage.json` — which functions each journey e
|
|
|
272
272
|
no scenario touches has never been run by anything but you, by hand, once.** It compiles, it
|
|
273
273
|
typechecks, `pikku all` is happy, and nobody has proven it does what it says.
|
|
274
274
|
|
|
275
|
-
Run it **as each
|
|
276
|
-
list you can act on — the
|
|
277
|
-
Read for the first time after ten
|
|
275
|
+
Run it **as each changeset closes**, not once at the end. Coverage read per changeset is a short
|
|
276
|
+
list you can act on — the changeset you just built either covered its own functions or it did not.
|
|
277
|
+
Read for the first time after ten changesets it is a wall of red that nobody triages, and the honest
|
|
278
278
|
response to a wall of red is to ignore it.
|
|
279
279
|
|
|
280
280
|
Every gap is one of three things, and naming which is the point of looking:
|
|
@@ -285,8 +285,8 @@ Every gap is one of three things, and naming which is the point of looking:
|
|
|
285
285
|
- **A function that should not exist** — nothing reaches it because nothing needs it. Delete it. An
|
|
286
286
|
unused exposed function is also reachable over `POST /rpc/:rpcName`, so this is a security finding,
|
|
287
287
|
not only dead weight.
|
|
288
|
-
- **Genuinely deferred** — real, not yet reachable from the UI.
|
|
289
|
-
|
|
288
|
+
- **Genuinely deferred** — real, not yet reachable from the UI. File it as a change, so the gap is
|
|
289
|
+
a decision rather than a hole.
|
|
290
290
|
|
|
291
|
-
Report the number when you hand the
|
|
291
|
+
Report the number when you hand the changeset over. A number nobody says out loud is a number nobody
|
|
292
292
|
acts on.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Shipping, and staying Fabric-ready
|
|
2
2
|
|
|
3
|
-
Read this when the
|
|
3
|
+
Read this when the changes queue is empty and the scenarios are green — it is
|
|
4
4
|
the last phase, and nothing in it is needed before then.
|
|
5
5
|
|
|
6
6
|
## Ship it — open source, no platform
|
|
@@ -128,8 +128,8 @@ bun run build # every frontend workspace, type-checked
|
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
Keep `--coverage` on the release run even though you have been reading it per
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
changeset (§7a). Each of those readings only covered the functions that
|
|
132
|
+
changeset added; this is the first time the whole surface is measured at once,
|
|
133
133
|
and it is where a function orphaned by a later refactor shows up.
|
|
134
134
|
|
|
135
135
|
**The last two lines are not optional, and one of them is easy to talk yourself
|
|
@@ -168,15 +168,15 @@ Everything above is open source. This is the contract that keeps
|
|
|
168
168
|
- **One `definePersonas` call**, every persona reachable through exactly one
|
|
169
169
|
frontend. Fabric materialises these as its virtual users; a persona nobody
|
|
170
170
|
serves imports as a person with no way in.
|
|
171
|
-
- **`knowledge/` passes `validate`,
|
|
171
|
+
- **`knowledge/` passes `validate`, and `pikku knowledge gaps` lists nothing.** This is
|
|
172
172
|
the part Fabric itself reads and continues from.
|
|
173
|
-
- **Every `
|
|
174
|
-
|
|
175
|
-
check. Anything the first pass still owes is either built now or deferred with
|
|
173
|
+
- **Every plan under `knowledge/plans/` passes `pikku knowledge plan progress`.**
|
|
174
|
+
A merged changeset is a claim; the plan reconciled against the generated meta
|
|
175
|
+
is the check. Anything the first pass still owes is either built now or deferred with
|
|
176
176
|
its reason on the record; anything the check calls a problem — something that
|
|
177
177
|
exists and does not do what was planned — is fixed, whatever pass it came from,
|
|
178
178
|
because deferring it defers a hole rather than the work.
|
|
179
|
-
- **Every
|
|
179
|
+
- **Every changeset has a passing scenario**, including its refusals.
|
|
180
180
|
- **Permissions live in the `permissions` field**, not in function bodies and not
|
|
181
181
|
in the frontends. A check hidden in a component does not survive a new client.
|
|
182
182
|
- **Nothing hardcodes a host, a port, or a `process.env` read inside a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-changes
|
|
3
|
-
description: 'Work a
|
|
3
|
+
description: 'Work a project''s changes queue — the todo list someone filed by circling things on a deployed stage. Covers `pikku changes wait|claim|show|ask|reply|shot|done`: waiting for work without polling, asking instead of guessing, saying why an item is left undone, offering options as images, one commit per item. TRIGGER when: the user says "run the pikkufabric changes", "run the changes against <stage>", "work the changes (queue)", "watch the changes", "pick up the changes", names a change by its #number, or you are otherwise idle in a checkout with open changes (`pikku changes list`). DO NOT TRIGGER for git changes, diffs or changelogs, and not for deploying or debugging a stage — use pikku-fabric for those.'
|
|
4
4
|
installGroups: [fabric]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -10,60 +10,107 @@ Someone walked the deployed app and circled things. Each item is their words, a
|
|
|
10
10
|
screenshot of what they saw, and the elements the circle enclosed. You have the repo.
|
|
11
11
|
Empty the queue without making them regret filing.
|
|
12
12
|
|
|
13
|
-
Run every command from the checkout
|
|
13
|
+
Run every command from the checkout. The queue lives in it (`.git/pikku-changes.json`, shared by every
|
|
14
|
+
worktree). When you are logged in to Fabric and the checkout is linked to a project (`pikku fabric config`
|
|
15
|
+
shows which), every write is also registered with Fabric.
|
|
14
16
|
`--json` works on all of them. Items are addressed as `2`, `#2` or their uuid.
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
**Launched by `pikku changes next`?** `pikku changes next` picks one agent: a merge conflict or a changeset with no plan
|
|
19
|
+
goes back to a changes agent; open changes go to a changes agent; a pikku version bump goes to an
|
|
20
|
+
upgrade agent, and knowledge no change builds yet (`pikku knowledge gaps`) to a knowledge agent — both
|
|
21
|
+
of those only file changes. A change filed for a gap ends its body with the gap's `Knowledge:` line.
|
|
22
|
+
As a changes agent, your work file already lists every open change. Skip the loop below,
|
|
23
|
+
group them into changesets, and take one: claim it, build it, mark its items done, stop. `pikku changes next --loop`
|
|
24
|
+
starts a fresh agent for the next one, so nothing you hold in context carries over — whatever the next
|
|
25
|
+
changeset needs to know goes in a commit or a `reply`.
|
|
21
26
|
|
|
22
27
|
## The loop
|
|
23
28
|
|
|
24
29
|
**Never poll.** No `sleep` loops, no repeated `list`, no re-running `show` to see if
|
|
25
|
-
something changed. `
|
|
30
|
+
something changed. `wait` does the waiting and exits only when there is work.
|
|
26
31
|
|
|
27
|
-
1. Start `
|
|
32
|
+
1. Start `wait` as a **background** command, and stop there until it exits:
|
|
28
33
|
|
|
29
34
|
```bash
|
|
30
|
-
pikku
|
|
35
|
+
pikku changes wait --claim --claimed-by claude-code
|
|
31
36
|
```
|
|
32
37
|
|
|
33
38
|
It waits out the grace window (a just-filed item is held about a minute so a batch
|
|
34
39
|
being typed arrives together), claims what is ready as one group, prints it, and
|
|
35
40
|
exits. It also wakes when someone answers a question you asked under that
|
|
36
|
-
`--claimed-by`. It
|
|
37
|
-
or answered, and sleeps exactly until a held item becomes claimable; when the event
|
|
38
|
-
stream is unavailable it falls back to checking every `--interval` seconds.
|
|
41
|
+
`--claimed-by`. It checks every `--interval` seconds.
|
|
39
42
|
|
|
40
43
|
2. When it exits, read the exit code:
|
|
41
44
|
|
|
42
45
|
| code | meaning | do |
|
|
43
46
|
| ---- | ------------------------------------------------------ | ----------------------------------------------- |
|
|
44
47
|
| 0 | work printed (claimed, and/or `Answered`) | work it, then step 3 |
|
|
45
|
-
| 2 | `--timeout`/`--once` found nothing | stop, or restart `
|
|
48
|
+
| 2 | `--timeout`/`--once` found nothing | stop, or restart `wait` |
|
|
46
49
|
| 3 | session refused | tell the user to run `pikku fabric login`; stop |
|
|
47
|
-
| 1 | anything else
|
|
50
|
+
| 1 | anything else | report the message; stop |
|
|
48
51
|
|
|
49
52
|
3. For each item: `show` → fix → commit → `done`; or `ask` and move on; or `reply`
|
|
50
|
-
saying why you are leaving it. Then start `
|
|
53
|
+
saying why you are leaving it. Then start `wait` again, in the background.
|
|
51
54
|
|
|
52
55
|
Without `--claim` it only reports what is claimable; claim it yourself:
|
|
53
56
|
|
|
54
57
|
```bash
|
|
55
|
-
pikku
|
|
58
|
+
pikku changes claim --change-ids 3,4 --title "Checkout pass" --claimed-by claude-code
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
A `claim` refused with a 409 says per item why — held for the filer, inside another
|
|
59
62
|
group's lease, done — and when a held or leased item is **claimable at** (a local
|
|
60
63
|
`HH:MM`; `list` and `show` print the same). An item inside someone else's live lease
|
|
61
|
-
cannot be taken. For held items, run `
|
|
64
|
+
cannot be taken. For held items, run `wait --claim` rather than retrying. The lease is 30 minutes
|
|
62
65
|
(`--lease-minutes`); an abandoned claim returns to the queue by itself.
|
|
63
66
|
|
|
67
|
+
## Changesets
|
|
68
|
+
|
|
69
|
+
Group related items into changesets and claim each one as a group, saying which tables it touches —
|
|
70
|
+
the entity notes' `resource:` lines name them:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pikku changes claim --change-ids 1,3 --title "Waitlist" --claimed-by pi --creates waitlist --reads booking
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The claim says whether the changeset needs a plan, and why: one that creates or alters a table, or
|
|
77
|
+
has many changes, always does; anything else goes to the judge configured with
|
|
78
|
+
`PIKKU_PLAN_JUDGE_URL` (any endpoint answering `{verdict, reason}` to `{question, context}`), and a
|
|
79
|
+
judge that fails says plan. With no judge configured only the fixed rules apply. `--needs-plan
|
|
80
|
+
true|false` overrides all of it.
|
|
81
|
+
|
|
82
|
+
A planned changeset is planned before any code, with the pikku-architect skill:
|
|
83
|
+
`pikku knowledge plan set <groupId> <file>` writes `knowledge/plans/<groupId>.plan.json`; commit it on
|
|
84
|
+
the changeset's branch. `done` refuses the first change until the plan reads and the last until
|
|
85
|
+
`pikku knowledge plan progress <groupId>` is clean, and `pikku changes next` will not merge a planned
|
|
86
|
+
changeset whose branch has no plan.
|
|
87
|
+
|
|
88
|
+
Build each changeset on its own branch, `changeset/<slug>`, cut from the branch you started on, one
|
|
89
|
+
commit per item (see Committing), and mark each item `done`. Launched by `pikku changes next`, stop there:
|
|
90
|
+
it merges finished changesets itself, as one `--no-ff` commit with a `Changeset:` trailer, and if the
|
|
91
|
+
merge conflicts it hands that back to an agent to resolve on the changeset's branch. Working by hand,
|
|
92
|
+
merge it yourself from the branch it goes into:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pikku changes merge --group-id <id>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Never `git merge` a changeset branch yourself — a fast-forward leaves no changeset commit, and
|
|
99
|
+
`changes merge` refuses a branch that is already in.
|
|
100
|
+
|
|
101
|
+
Changesets that create or alter tables go one at a time; one that reads a table waits for the
|
|
102
|
+
changeset creating it; the rest can run side by side. On the local queue, `claim` refuses a changeset
|
|
103
|
+
that would break that order, and `done` refuses a commit that adds a migration under `db/` when its
|
|
104
|
+
changeset declared no `--creates`/`--alters`.
|
|
105
|
+
|
|
106
|
+
When other agents are working changesets at the same time (your work says so), claim with
|
|
107
|
+
`--worktree`: it creates `changeset/<slug>` in its own checkout beside the repo and prints the path.
|
|
108
|
+
Build and commit there and run `done` there; the merge removes the worktree. If the claim is refused because of a running changeset, claim one that does not
|
|
109
|
+
clash, or stop.
|
|
110
|
+
|
|
64
111
|
## Reading an item
|
|
65
112
|
|
|
66
|
-
`pikku
|
|
113
|
+
`pikku changes show 3` gives, most trustworthy first:
|
|
67
114
|
|
|
68
115
|
1. **Their words.** The title and body are the requirement. Everything else is evidence.
|
|
69
116
|
2. **The screenshot.** What they saw, at their width, with their data. When the other
|
|
@@ -84,11 +131,11 @@ One decision, in their vocabulary, with the choices as `--option` flags — each
|
|
|
84
131
|
a button. Include "hold until I check" when it is real. Batch questions per group.
|
|
85
132
|
|
|
86
133
|
```bash
|
|
87
|
-
pikku
|
|
134
|
+
pikku changes ask --change-id 3 --question "Make the total stand out — which way?" \
|
|
88
135
|
--option "Bigger" --option "Move it above the delivery line" --author-name claude-code
|
|
89
136
|
```
|
|
90
137
|
|
|
91
|
-
Then **park it** and move on. The answer wakes `
|
|
138
|
+
Then **park it** and move on. The answer wakes `wait` (same `--claimed-by`); it prints
|
|
92
139
|
under `Answered`, and `show` has the reply.
|
|
93
140
|
|
|
94
141
|
If the answer is visual and you can build it, build each variant, screenshot all of
|
|
@@ -96,7 +143,7 @@ them in one pass at one width (baseline included), and attach them — the panel
|
|
|
96
143
|
`--kind option` shots into a pick-one:
|
|
97
144
|
|
|
98
145
|
```bash
|
|
99
|
-
pikku
|
|
146
|
+
pikku changes shot --change-id 3 --label "Bigger" --kind option --image a.png
|
|
100
147
|
```
|
|
101
148
|
|
|
102
149
|
`--kind evidence` is a picture that proves something, shown inline.
|
|
@@ -112,7 +159,7 @@ item's status exactly where it was:
|
|
|
112
159
|
- you could not reproduce it — attach what you saw.
|
|
113
160
|
|
|
114
161
|
```bash
|
|
115
|
-
pikku
|
|
162
|
+
pikku changes reply 3 --message "Cannot reproduce on develop @ a91c4e2 — this is what I see." \
|
|
116
163
|
--image seen.png --image-label "develop @ a91c4e2" --author-name claude-code
|
|
117
164
|
```
|
|
118
165
|
|
|
@@ -135,12 +182,11 @@ Scope names the screen they were looking at, not the file you edited.
|
|
|
135
182
|
## Finishing
|
|
136
183
|
|
|
137
184
|
```bash
|
|
138
|
-
pikku
|
|
185
|
+
pikku changes done --change-id 7 --note "What you did, for whoever reads the thread"
|
|
139
186
|
```
|
|
140
187
|
|
|
141
|
-
Branch and commit default to the checkout you are in — run it there, never type a sha.
|
|
188
|
+
Branch and commit default to the checkout you are in — run it there, never type a sha. `done` finds the item's commit by its `Change-Id` trailer, so close items in any order.
|
|
142
189
|
An item you decided not to do is not `done`: `reply` with why and leave it for a
|
|
143
190
|
human to dismiss.
|
|
144
191
|
|
|
145
|
-
|
|
146
|
-
`--claim` are reads.
|
|
192
|
+
Registering writes with Fabric needs the `changes:project:write` scope.
|
|
@@ -4,11 +4,11 @@ description: >-
|
|
|
4
4
|
Use when writing, reading, reorganising or validating a project's knowledge/ directory — the
|
|
5
5
|
notes that say what the app is, in the language its users use. Covers the Open Knowledge Format
|
|
6
6
|
note (path-as-identity markdown, YAML frontmatter, only `type` required), the app-project
|
|
7
|
-
profile's sections (
|
|
8
|
-
|
|
9
|
-
what is NOT a knowledge base, and `pikku knowledge validate|index`. TRIGGER when: user asks to
|
|
7
|
+
profile's sections (entities, decisions, questions, wishlist) and what each answers, how notes
|
|
8
|
+
become changes (`pikku knowledge gaps`), the changeset plan, the `resource:` URI scheme tying a
|
|
9
|
+
note to its code, what is NOT a knowledge base, and `pikku knowledge validate|index|gaps`. TRIGGER when: user asks to
|
|
10
10
|
write down a decision, requirement, entity or open question; asks what the app does or is; asks
|
|
11
|
-
about knowledge/, notes,
|
|
11
|
+
about knowledge/, notes, an index.md, or a diagram, callout or decision block; or
|
|
12
12
|
hands over a product brief to record. DO NOT TRIGGER when: user asks what functions, routes,
|
|
13
13
|
tables or permissions exist (that is `pikku meta` / `pikku info`, never a note), or to write a
|
|
14
14
|
scenario test (use pikku-scenario).
|
|
@@ -75,7 +75,7 @@ Frontmatter fields:
|
|
|
75
75
|
|
|
76
76
|
| Field | Meaning |
|
|
77
77
|
| ------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
78
|
-
| `type` | **The only required field.** One of `
|
|
78
|
+
| `type` | **The only required field.** One of `entity`, `decision`, `note`, `overview`. Lowercase — every gate compares it literally, so a near-miss is a note no command can see. |
|
|
79
79
|
| `title` | What to call the note in a listing. Falls back to the first heading, then the filename. |
|
|
80
80
|
| `description` | One line, used as the note's subtitle in a section index. |
|
|
81
81
|
| `resource` | Comma-separated `<kind>:<id>` URIs — the code this note is about. See below. |
|
|
@@ -91,9 +91,6 @@ Plain markdown links between notes — `[revocation](../decisions/revocation-end
|
|
|
91
91
|
```
|
|
92
92
|
knowledge/
|
|
93
93
|
index.md # type: overview — the map
|
|
94
|
-
milestones/
|
|
95
|
-
index.md
|
|
96
|
-
01-the-daily-entry.md # type: milestone
|
|
97
94
|
entities/
|
|
98
95
|
index.md
|
|
99
96
|
entry.md # type: entity
|
|
@@ -115,7 +112,6 @@ Each section answers exactly one question, which is what lets a reader find a no
|
|
|
115
112
|
|
|
116
113
|
| Section | The question it answers |
|
|
117
114
|
| --------------------- | ------------------------------------------------------------------ |
|
|
118
|
-
| `milestones/` | What is one buildable piece of this app, and what proves it works? |
|
|
119
115
|
| `entities/` | What is this thing, in the words users use for it? |
|
|
120
116
|
| `decisions/` | What was chosen, and what does that rule out? |
|
|
121
117
|
| `decisions/security/` | Who may do what? |
|
|
@@ -124,36 +120,31 @@ Each section answers exactly one question, which is what lets a reader find a no
|
|
|
124
120
|
|
|
125
121
|
**Create a section the turn you have a note for it** — never a scaffold of empty directories, and never a section without its own `index.md`. A section index says in one line what belongs in it; that sentence is the reason the file exists, so `pikku knowledge index` writes only the note listing and leaves your prose alone.
|
|
126
122
|
|
|
127
|
-
##
|
|
128
|
-
|
|
129
|
-
A milestone is the one note type that is a piece of _work_ rather than a fact, so it alone carries state and size. It lives in `knowledge/milestones/` and nowhere else: `readMilestones` matches on that directory literally, so the same note under another section is invisible to every gate and command below.
|
|
123
|
+
## Work is changes, not notes
|
|
130
124
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
description: An owner writes one entry per day, and sees it on the day.
|
|
136
|
-
status: proposed
|
|
137
|
-
entities: entry, day
|
|
138
|
-
resource: func:createEntry
|
|
139
|
-
---
|
|
125
|
+
The base says what the app IS. What still has to be built is not written here: it is filed as
|
|
126
|
+
**changes** on the project's queue (`pikku changes file`), grouped into changesets, and built
|
|
127
|
+
one commit per change — the pikku-changes skill. A note never carries status, size or a gherkin
|
|
128
|
+
block; a behaviour the app must have is a sentence in the note it is about.
|
|
140
129
|
|
|
141
|
-
|
|
130
|
+
```bash
|
|
131
|
+
pikku knowledge gaps # the notes no change builds yet
|
|
132
|
+
```
|
|
142
133
|
|
|
143
|
-
|
|
134
|
+
`gaps` compares the notes against the plans of merged changesets and the changes already filed:
|
|
144
135
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
````
|
|
136
|
+
- **`uncovered`** — no plan covers the note.
|
|
137
|
+
- **`changed`** — the note was edited after the changeset that built it merged.
|
|
138
|
+
- **`partial`** — it merged with items deferred; they are listed.
|
|
139
|
+
- **`removed`** — code a merged changeset built for the note is gone from the generated meta.
|
|
140
|
+
- **`deleted`** — the note is gone and the code a changeset built for it is not.
|
|
152
141
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
142
|
+
The first three are work: file a change for each, and end its body with the gap's
|
|
143
|
+
`Knowledge: <note>@<hash>` line so it is not filed again. The last two mean the code and the
|
|
144
|
+
knowledge disagree about something that was built — read `git log` for who removed it and why, then
|
|
145
|
+
either bring the knowledge into line (edit or delete the note, or file a change that removes the
|
|
146
|
+
code) or file a change that restores it. When you cannot tell which, file the change and ask on it.
|
|
147
|
+
`pikku changes next` hands open gaps to a knowledge agent when there is nothing else to do.
|
|
157
148
|
|
|
158
149
|
## Showing it
|
|
159
150
|
|
|
@@ -230,7 +221,7 @@ These are all things that exist somewhere better, so a note is always the copy t
|
|
|
230
221
|
| Do not write | Because it lives in |
|
|
231
222
|
| ----------------------------------- | ---------------------------------------------------------- |
|
|
232
223
|
| a `personas/` section | `definePersonas()` in the project's own code |
|
|
233
|
-
| a `scenarios/` section | the
|
|
224
|
+
| a `scenarios/` section | the `scenarios` of the plan for the changeset that builds it |
|
|
234
225
|
| a `permissions/` section | a decision note under `decisions/security/` |
|
|
235
226
|
| a list of tables, columns or routes | `pikku meta` — the generated schema _is_ the schema |
|
|
236
227
|
| a changelog | `CHANGELOG.md` at the repo root |
|
|
@@ -249,66 +240,35 @@ pikku knowledge index # refresh every index.md
|
|
|
249
240
|
pikku knowledge index --check # report stale indexes without writing (CI gate)
|
|
250
241
|
```
|
|
251
242
|
|
|
252
|
-
`validate` reports: notes with no `type`, a missing `knowledge/index.md`, a section with no `index.md`, notes flat at the root, sections that duplicate what the project already declares,
|
|
243
|
+
`validate` reports: notes with no `type`, a missing `knowledge/index.md`, a section with no `index.md`, notes flat at the root, sections that duplicate what the project already declares, plans under `knowledge/plans/` that do not read or contradict themselves, `decision` fences that state no `chosen:` or rule nothing out, and every `resource:` that no longer resolves. Errors fail the command; warnings do not.
|
|
253
244
|
|
|
254
245
|
`index` rewrites only the block between `<!-- pikku:knowledge-index -->` markers, creating a scaffolded `index.md` for a section that has none. It is idempotent — running it twice changes nothing.
|
|
255
246
|
|
|
256
|
-
###
|
|
257
|
-
|
|
258
|
-
```bash
|
|
259
|
-
pikku knowledge next # the one thing to do next, derived from what is on disk
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
`next` is a pure read: it looks at the notes and answers with exactly one action —
|
|
263
|
-
`repair-note`, `write-plan`, `ask-user`, `dispatch`, `hold`, or `idle`. Nothing has to
|
|
264
|
-
be armed by whoever noticed a transition, so calling it twice is free and a state
|
|
265
|
-
nobody anticipated is a missing answer rather than a run that quietly stops.
|
|
266
|
-
|
|
267
|
-
Two things about the output matter if you are driving it:
|
|
268
|
-
|
|
269
|
-
- **`reason` is machine wording.** It names the note, the frontmatter key and what the
|
|
270
|
-
gate wanted. Never repeat it to a person — they have not seen a note and it will read
|
|
271
|
-
as gibberish about files.
|
|
272
|
-
- **`ask-user` carries a `question` as well.** That IS the version for a person: a
|
|
273
|
-
`header`, the question in the language of their app, and `options` when the answer
|
|
274
|
-
comes from a closed vocabulary (which `status:` it is, which `surface:` it is).
|
|
275
|
-
`options` is empty when the answer is free text, and an empty list means offer free
|
|
276
|
-
text — never invent choices to fill it.
|
|
247
|
+
### The changeset plan
|
|
277
248
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### The milestone plan
|
|
283
|
-
|
|
284
|
-
A milestone note says what the app must DO. Its **plan** — JSON beside the note, not prose — says what has to exist for it, and is what a finished build is measured against:
|
|
249
|
+
A changeset that creates or alters a table, or that the judge says needs one, is planned before any
|
|
250
|
+
of its code. The **plan** — JSON at `knowledge/plans/<changeset>.plan.json`, committed on the
|
|
251
|
+
changeset's branch — says what has to exist for it, which notes it `covers`, and is what a finished
|
|
252
|
+
build is measured against:
|
|
285
253
|
|
|
286
254
|
```bash
|
|
287
255
|
pikku knowledge plan schema # the format, in full
|
|
288
|
-
pikku knowledge plan set <
|
|
289
|
-
pikku knowledge plan show <
|
|
290
|
-
pikku knowledge plan progress <
|
|
291
|
-
pikku knowledge plan defer <
|
|
256
|
+
pikku knowledge plan set <changeset> <file> # validate and write it
|
|
257
|
+
pikku knowledge plan show <changeset> --for-build # the ordered work a build follows
|
|
258
|
+
pikku knowledge plan progress <changeset> # what it still owes, read from .pikku/
|
|
259
|
+
pikku knowledge plan defer <changeset> <item> -r "<why>"
|
|
292
260
|
```
|
|
293
261
|
|
|
294
|
-
`progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. How a plan is written is `pikku-architect`; building against one
|
|
295
|
-
|
|
296
|
-
### A finished milestone is a tombstone
|
|
297
|
-
|
|
298
|
-
**Once a milestone reaches `built`, its note and its plan are closed. Do not edit either.** Not to correct the wording, not to fold in what the build actually turned out to need, not to add the item everyone agrees should have been there. A finished milestone is the record of what was agreed and what was measured against it, and a record that can be revised afterwards measures nothing.
|
|
299
|
-
|
|
300
|
-
This is the rule the shape of the thing already implies. `progress` reconciles a plan against generated meta and fails when what shipped contradicts it — a check with no force at all if the losing side of the contradiction may simply be rewritten. `attempts:` brakes a note nothing can satisfy, and refunds that budget when the note's content really changes; a `built` note that keeps changing is that brake removed. Both only work while the plan stays still.
|
|
262
|
+
`progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. How a plan is written is `pikku-architect`; building against one is `pikku-changes`, whose `done` refuses the last change of a planned changeset until `progress` is clean.
|
|
301
263
|
|
|
302
|
-
|
|
264
|
+
### A merged plan is a tombstone
|
|
303
265
|
|
|
304
|
-
|
|
305
|
-
- It was built differently than planned → that is what `progress` is for. Reconcile forward, or record a decision saying why the plan was not the right shape.
|
|
306
|
-
- It was simply wrong → a decision note that supersedes it. The wrong milestone stays where it is; a base whose history is edited cannot answer *why* anything is the way it is, which is most of what a base is for.
|
|
266
|
+
**Once a changeset merges, its plan is closed. Do not edit it.** Not to correct the wording, not to fold in what the build actually turned out to need. A merged plan is the record of what was agreed and what was measured against it, and a record that can be revised afterwards measures nothing.
|
|
307
267
|
|
|
308
|
-
|
|
268
|
+
Notes are different: they say what the app is now, so they change whenever it does. Editing a note a merged changeset covered is exactly how new work arrives — `gaps` reads it as `changed`, and it is filed again.
|
|
309
269
|
|
|
310
270
|
## Profiles built on this one
|
|
311
271
|
|
|
312
272
|
OKF permits frontmatter fields a reader does not know, and the parser ignores them rather than failing. That is the extension point: a tool layered on Pikku can add its own sections and fields on top of everything above without forking the format.
|
|
313
273
|
|
|
314
|
-
Fabric is the one that exists. It adds `decisions/design/` — rules about how the app looks and behaves — a `screens/` section
|
|
274
|
+
Fabric is the one that exists. It adds `decisions/design/` — rules about how the app looks and behaves — and a `screens/` section. Both are Fabric's to validate; `pikku knowledge validate` passes them through untouched. Everything else in this skill is the same in both.
|