create-pathfinder 1.7.0 → 1.8.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/CLAUDE.md +2 -0
- package/README.md +1 -1
- package/context/ai-interaction.md +1 -0
- package/package.json +1 -1
- package/skills/complete-feature/SKILL.md +3 -2
- package/skills/load-feature/SKILL.md +2 -1
- package/skills/setup-tracker/SKILL.md +74 -0
- package/skills/start-feature/SKILL.md +1 -0
- package/skills/sync-tracker/SKILL.md +120 -0
- package/skills/to-specs/SKILL.md +4 -0
- package/src/detect.mjs +1 -1
- package/src/kickstart-prompt.mjs +1 -1
- package/templates/feature-spec.template.md +6 -0
- package/templates/tracker.template.md +359 -0
package/CLAUDE.md
CHANGED
|
@@ -76,3 +76,5 @@ An adapter carries the canonical skill's frontmatter and a pointer to it, and no
|
|
|
76
76
|
- `reflect` — review completed work, and the reflection itself, and propose reusable workflow improvements for human approval
|
|
77
77
|
- `handoff` — preserve useful state between sessions or tools
|
|
78
78
|
- `skillsmith` — teach and create small local skills
|
|
79
|
+
- `setup-tracker` — configure an optional external work tracker
|
|
80
|
+
- `sync-tracker` — publish approved feature specs to the configured tracker, one-way and idempotently
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The installer copies five things into your repository and nothing else:
|
|
|
27
27
|
| --- | --- |
|
|
28
28
|
| `AGENTS.md`, `CLAUDE.md` | Entry files that tell an agent how to work in the project |
|
|
29
29
|
| `context/` | Project truth — overview, standards, interaction rules, current feature |
|
|
30
|
-
| `skills/` |
|
|
30
|
+
| `skills/` | Skills covering discovery, specs, delivery, debugging, review, learning, and optional work tracking |
|
|
31
31
|
| `templates/` | Starting points the project copies when it needs them |
|
|
32
32
|
|
|
33
33
|
On request it also writes one thing it does not copy:
|
|
@@ -20,6 +20,7 @@ Follow the project's documented policy. Unless explicitly pre-approved, ask befo
|
|
|
20
20
|
- Git history rewriting
|
|
21
21
|
- commits, merges, releases, or deployments
|
|
22
22
|
- adopting prototype code into production
|
|
23
|
+
- writes that leave this repository, such as creating or editing items on a shared work tracker — writing files inside the repository is an ordinary file edit and is not covered
|
|
23
24
|
|
|
24
25
|
## Git and Delivery
|
|
25
26
|
|
package/package.json
CHANGED
|
@@ -11,7 +11,8 @@ description: Close an accepted feature through final verification, records, deli
|
|
|
11
11
|
4. Follow the approved commit, PR, merge, changelog, versioning, release, and deployment policy—requesting approval where required. After the merge, verify the merged mainline and clean up the merged branch as that policy requires.
|
|
12
12
|
5. Append the durable outcome to `context/history.md` while completing the feature, not afterwards. If the feature was merged without this skill running, still write the entry and record that it was written after the fact.
|
|
13
13
|
6. Mark/reset `context/current-feature.md` and identify the next action.
|
|
14
|
-
7.
|
|
15
|
-
8.
|
|
14
|
+
7. If `context/tracker.md` exists, reconcile this feature's tracked item with `sync-tracker` after the merge.
|
|
15
|
+
8. Offer or invoke `learn-feature` when learning is enabled.
|
|
16
|
+
9. Produce a compact completion summary.
|
|
16
17
|
|
|
17
18
|
Do not claim completion when checks failed, evidence is missing, or the feature remains unaccepted.
|
|
@@ -12,6 +12,7 @@ description: Prepare one feature for implementation by checking readiness, conte
|
|
|
12
12
|
5. Assess whether the feature fits a focused LLM context window.
|
|
13
13
|
6. Split or revise it before implementation if the context is too broad.
|
|
14
14
|
7. Populate `context/current-feature.md` with the feature, first delivery chunk, context boundary, assumptions, Git state, definition of done, and out-of-scope work.
|
|
15
|
-
8.
|
|
15
|
+
8. If `context/tracker.md` exists, note this feature's tracked item, or that it has none yet. The lookup is best-effort: an unreachable tracker is reported and never blocks loading.
|
|
16
|
+
9. Present a short readiness summary.
|
|
16
17
|
|
|
17
18
|
Do not implement, create Git history, or resolve `TBD` decisions silently.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-tracker
|
|
3
|
+
description: Configure an optional external work tracker by interviewing the human and writing context/tracker.md from the shipped template.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Setup Tracker
|
|
7
|
+
|
|
8
|
+
Use this skill to describe, in prose, which tracker a project uses and how
|
|
9
|
+
Pathfinder's work items project onto it. The result is `context/tracker.md`.
|
|
10
|
+
|
|
11
|
+
Work Tracking is **optional**. A project that never runs this skill is
|
|
12
|
+
unaffected: no file, no prompt, no behaviour change anywhere. Do not run this
|
|
13
|
+
skill unasked, and do not propose it as a missing step.
|
|
14
|
+
|
|
15
|
+
This skill configures. It never contacts a tracker.
|
|
16
|
+
|
|
17
|
+
## Rules
|
|
18
|
+
|
|
19
|
+
- Do not write `context/tracker.md` without human approval.
|
|
20
|
+
- Do not add code, dependencies, or an adapter for any tracker.
|
|
21
|
+
- Do not invent a taxonomy the team did not ask for.
|
|
22
|
+
- Keep the model section backend-neutral; vendor vocabulary belongs only under
|
|
23
|
+
the projection heading.
|
|
24
|
+
- Never remove the work-item marker block. It is the one machine-stable token in
|
|
25
|
+
a prose contract, and identity depends on it.
|
|
26
|
+
|
|
27
|
+
## Interview
|
|
28
|
+
|
|
29
|
+
Ask progressively, in small groups. Ask only what the config cannot be written
|
|
30
|
+
without:
|
|
31
|
+
|
|
32
|
+
1. Which tracker, and where it lives.
|
|
33
|
+
2. How an agent reaches it — a CLI, a path, or a described manual step.
|
|
34
|
+
3. Which tag namespaces the project actually uses. `area`, `type`, `priority`,
|
|
35
|
+
and `agent` are available; a project needing none of them says so.
|
|
36
|
+
4. What the tracker already carries. **List its existing labels, fields, or
|
|
37
|
+
conventions before proposing any tag value.** If something already means the
|
|
38
|
+
same thing, reuse it and record the mapping rather than creating a
|
|
39
|
+
near-duplicate.
|
|
40
|
+
5. Anything about the projection that the shipped starting points do not cover.
|
|
41
|
+
|
|
42
|
+
## Process
|
|
43
|
+
|
|
44
|
+
1. Check whether `context/tracker.md` already exists. If it does, read it, and
|
|
45
|
+
treat this run as a revision — show what would change and change nothing
|
|
46
|
+
else. Never overwrite a working config wholesale.
|
|
47
|
+
2. Read `templates/tracker.template.md`.
|
|
48
|
+
3. Run the interview.
|
|
49
|
+
4. Choose the projection:
|
|
50
|
+
- **GitHub Issues via `gh`** and **local Markdown files** ship as starting
|
|
51
|
+
points, both proven.
|
|
52
|
+
- Any other tracker is supported by the human describing it in prose, using a
|
|
53
|
+
shipped projection as the shape to follow. **That is the mechanism, not a
|
|
54
|
+
gap** — do not report an unsupported tracker as a blocker.
|
|
55
|
+
5. Fill the placeholders and keep **one** projection block. Delete, in the
|
|
56
|
+
written config:
|
|
57
|
+
- the template's guidance blockquote at the top;
|
|
58
|
+
- the projection block you did not keep;
|
|
59
|
+
- the `pathfinder:model-start` and `pathfinder:projection-boundary` markers;
|
|
60
|
+
- the italic *"Keep this block for…"* line under the projection you kept — it
|
|
61
|
+
is an instruction to you, not content for the project to read.
|
|
62
|
+
|
|
63
|
+
**The model — everything between the two markers — is kept byte-for-byte.**
|
|
64
|
+
The tracker-identity paragraph above it is the one part you rewrite, because
|
|
65
|
+
it names the tracker and how to reach it.
|
|
66
|
+
6. Present the proposed file and request approval.
|
|
67
|
+
7. Write `context/tracker.md` only after the human approves.
|
|
68
|
+
8. Report what was configured, and say plainly that nothing has been published.
|
|
69
|
+
|
|
70
|
+
## Stop Condition
|
|
71
|
+
|
|
72
|
+
Stop once the config is written. Publishing to a tracker is `sync-tracker`, not
|
|
73
|
+
this skill. If `sync-tracker` is not installed, say so rather than publishing by
|
|
74
|
+
hand.
|
|
@@ -23,3 +23,4 @@ Restate goal, chunk, files/areas, context, risks, assumptions, verification, exc
|
|
|
23
23
|
- Stop on conflicts between spec, durable context, and repository reality.
|
|
24
24
|
- Do not add dependencies, expand scope, adopt prototype code, commit, merge, or deploy without the documented approval.
|
|
25
25
|
- Do not hide multiple features inside one delivery chunk.
|
|
26
|
+
- Do not publish to a work tracker, even when `context/tracker.md` exists — the repository is canonical and a chunk boundary is not a tracker event.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-tracker
|
|
3
|
+
description: Publish approved feature specs to the configured work tracker, one-way and idempotently, writing nothing when nothing has changed.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sync Tracker
|
|
7
|
+
|
|
8
|
+
Use this skill to project the project's approved feature specs onto the tracker
|
|
9
|
+
described in `context/tracker.md`.
|
|
10
|
+
|
|
11
|
+
The repository is canonical. This is a **one-way projection** of work that
|
|
12
|
+
already exists. Nothing here reads tracker state back into a spec,
|
|
13
|
+
`context/current-feature.md`, or `context/history.md`.
|
|
14
|
+
|
|
15
|
+
## The off switch comes first
|
|
16
|
+
|
|
17
|
+
**If `context/tracker.md` does not exist, do nothing at all.** Report that work
|
|
18
|
+
tracking is not configured for this project, and stop.
|
|
19
|
+
|
|
20
|
+
Do not create the config, do not propose configuring one, and do not describe
|
|
21
|
+
its absence as a gap. Work Tracking is optional, and a project without it is
|
|
22
|
+
behaving correctly.
|
|
23
|
+
|
|
24
|
+
## The config is the contract
|
|
25
|
+
|
|
26
|
+
Read `context/tracker.md` in full and follow its prose. It states the model, the
|
|
27
|
+
projection, and the publishing rules for this project.
|
|
28
|
+
|
|
29
|
+
There is **no adapter code, no vendor branch, and no required tool** beyond what
|
|
30
|
+
the config itself names. If the config describes a tracker this skill has never
|
|
31
|
+
heard of, that is the design working, not a blocker.
|
|
32
|
+
|
|
33
|
+
Where the config is silent on something a run needs, **ask the human**. Do not
|
|
34
|
+
fill the gap with a convention of your own — the next run would fill it
|
|
35
|
+
differently, and every item would look modified.
|
|
36
|
+
|
|
37
|
+
## What gets published
|
|
38
|
+
|
|
39
|
+
**Approved feature specs only**, from `to-specs` onward — one work item per spec.
|
|
40
|
+
Never debate notes, kickstart output, or prototypes. The one exception is a
|
|
41
|
+
prototype that gates a decision, published as a single item phrased as the
|
|
42
|
+
decision it resolves, never as a deliverable.
|
|
43
|
+
|
|
44
|
+
**Do not decompose a feature.** Choosing units of execution inside a feature is a
|
|
45
|
+
judgement about how work will be shared out, and it belongs to a human or to a
|
|
46
|
+
skill written for it. Publish the feature.
|
|
47
|
+
|
|
48
|
+
## Process
|
|
49
|
+
|
|
50
|
+
1. Check for `context/tracker.md`. If it is absent, report and stop.
|
|
51
|
+
2. Read the config. Read the approved specs. Read nothing else.
|
|
52
|
+
3. Build the work items: key, kind, title, body, blocked-by edges, tags, and
|
|
53
|
+
chunks, derived and composed exactly as the config's model section says. Every
|
|
54
|
+
field comes from the spec — **tags only from its optional `## Tags` section,
|
|
55
|
+
never inferred.** A spec without one has no tags, which is correct and common.
|
|
56
|
+
4. Order them by dependency, blockers first. If the edges contain a cycle,
|
|
57
|
+
report it and publish nothing — a guessed order is a wrong order that looks
|
|
58
|
+
fine.
|
|
59
|
+
5. **Ask the human before the first write that leaves this repository.** See
|
|
60
|
+
below.
|
|
61
|
+
6. Publish, following the config's *Publishing, and re-publishing* section
|
|
62
|
+
exactly: index existing items by key, create what is missing, compare
|
|
63
|
+
normalized, and leave an unchanged item completely alone.
|
|
64
|
+
7. Report what was created, what was edited, and what was left alone.
|
|
65
|
+
|
|
66
|
+
## The approval gate
|
|
67
|
+
|
|
68
|
+
**Ask before the first write to a tracker outside this repository in a session.**
|
|
69
|
+
Creating items on a shared board is outward-facing and is not covered by ordinary
|
|
70
|
+
file-edit approval. One approval covers the run; do not ask per item.
|
|
71
|
+
|
|
72
|
+
**A projection onto files inside this repository is not gated.** It is an
|
|
73
|
+
ordinary file edit and reaches nothing outside the repository. The gate is about
|
|
74
|
+
leaving the repository, not about writing.
|
|
75
|
+
|
|
76
|
+
## Idempotency is the whole feature
|
|
77
|
+
|
|
78
|
+
A second run over unchanged specs must **create nothing, change nothing, and
|
|
79
|
+
issue zero writes**. Not writes that happen to be no-ops — no writes.
|
|
80
|
+
|
|
81
|
+
- **Compare normalized, never raw bytes.** A tracker is not obliged to hand a
|
|
82
|
+
body back exactly as it was sent, and APIs differ in whether they adjust
|
|
83
|
+
trailing whitespace. Where that happens, a naive byte comparison reports every
|
|
84
|
+
item as changed on every run and rewrites all of them forever, which looks like
|
|
85
|
+
working sync and is not. Strip trailing whitespace from each line and collapse
|
|
86
|
+
trailing blank lines at the end, **on both sides**, before comparing. It costs
|
|
87
|
+
nothing when the round-trip is exact.
|
|
88
|
+
- **Compare tag sets as sets**, not as ordered lists. Application order is not
|
|
89
|
+
preserved.
|
|
90
|
+
- Never close, reopen, delete, or recreate an item. Edit in place.
|
|
91
|
+
- Never touch an item whose key is absent from the current set. It belongs to
|
|
92
|
+
work outside this run.
|
|
93
|
+
- Match on the key alone, never on the title.
|
|
94
|
+
|
|
95
|
+
**Report writes, not final state.** "The tracker looks right" is satisfied by a
|
|
96
|
+
run that rewrote every item, which is the specific failure this skill exists to
|
|
97
|
+
avoid. `3 items, 0 changes` is the expected result of a second run and the most
|
|
98
|
+
important line of output.
|
|
99
|
+
|
|
100
|
+
## Rules
|
|
101
|
+
|
|
102
|
+
- Do not add code, dependencies, or an adapter for any tracker.
|
|
103
|
+
- Do not branch on `kind`.
|
|
104
|
+
- Do not infer tags, and do not apply a value the config's mapping table does not
|
|
105
|
+
carry. A spec naming an unmapped tag is a question for the human, not a
|
|
106
|
+
judgement call.
|
|
107
|
+
- Do not drop an edge that resolves outside the published set, and do not invent
|
|
108
|
+
an item for it. Resolve it against the tracker as a whole: render the item's
|
|
109
|
+
identifier if the key already has one, and name the key as untracked only when
|
|
110
|
+
it genuinely has none.
|
|
111
|
+
- Do not read anything back. A ticked checkbox means nothing to Pathfinder and
|
|
112
|
+
never advances any state.
|
|
113
|
+
- Do not close, reopen, or delete anything, ever.
|
|
114
|
+
- Stop and report when the config, the specs, and the tracker disagree.
|
|
115
|
+
|
|
116
|
+
## Stop Condition
|
|
117
|
+
|
|
118
|
+
Stop once the run is reported. Configuring a tracker is `setup-tracker`, not this
|
|
119
|
+
skill. If a spec set is not ready to publish, say so rather than publishing part
|
|
120
|
+
of it.
|
package/skills/to-specs/SKILL.md
CHANGED
|
@@ -36,8 +36,12 @@ Create only the coherent MVP roadmap in `context/features/`, using `templates/fe
|
|
|
36
36
|
|
|
37
37
|
Each spec must include Context Boundary, Delivery Chunks, and Learning Targets.
|
|
38
38
|
|
|
39
|
+
Write a `## Tags` section only when the project has configured work tracking and its `context/tracker.md` defines tag namespaces. Use the values that config already lists, never invented ones. No tags is a valid and common answer — omit the section rather than guessing.
|
|
40
|
+
|
|
39
41
|
After creation, summarize file, outcome, dependency, visible/verifiable win, context risk, and recommended first feature.
|
|
40
42
|
|
|
43
|
+
If `context/tracker.md` exists, offer to publish the new specs with `sync-tracker`. If it does not, say nothing about tracking.
|
|
44
|
+
|
|
41
45
|
## Rules
|
|
42
46
|
|
|
43
47
|
- Do not implement or install packages.
|
package/src/detect.mjs
CHANGED
|
@@ -119,7 +119,7 @@ function detectTool(tool, { cwd, home, env, platform }) {
|
|
|
119
119
|
* Decided by counting skill directories rather than by testing for `CLAUDE.md`,
|
|
120
120
|
* which any agent-assisted project may have written for its own reasons.
|
|
121
121
|
* A `skills/<name>/SKILL.md` is a far more specific signature, and the count is
|
|
122
|
-
* worth having on its own — it is what makes "already installed (
|
|
122
|
+
* worth having on its own — it is what makes "already installed (N skills)"
|
|
123
123
|
* checkable by the person reading it.
|
|
124
124
|
*/
|
|
125
125
|
function detectPathfinder(cwd) {
|
package/src/kickstart-prompt.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This used to be one hardcoded string naming a file path, and that was right
|
|
5
5
|
* for exactly as long as Pathfinder configured nothing. Once a run can generate
|
|
6
6
|
* native adapters, the path form is no longer the best answer for someone who
|
|
7
|
-
* just watched
|
|
7
|
+
* just watched the whole kit be installed into their harness — it is the answer
|
|
8
8
|
* for someone whose tool cannot discover them.
|
|
9
9
|
*
|
|
10
10
|
* A pure function of the selection, deliberately: no filesystem, no detection,
|
|
@@ -22,6 +22,12 @@ State one user-visible or system-verifiable outcome.
|
|
|
22
22
|
|
|
23
23
|
- Earlier feature, system, decision, prototype, or `None`.
|
|
24
24
|
|
|
25
|
+
## Tags
|
|
26
|
+
|
|
27
|
+
- Optional. `namespace:value`, e.g. `area:cli`, `type:infra`, `agent:suitable`.
|
|
28
|
+
- Omit this section entirely, or write `None`, when the project does not use tags. Most do not.
|
|
29
|
+
- Only meaningful when the project has configured work tracking; nothing else reads them.
|
|
30
|
+
|
|
25
31
|
## Requirements
|
|
26
32
|
|
|
27
33
|
- Requirement 1
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Tracker
|
|
2
|
+
|
|
3
|
+
> Starting point for `context/tracker.md`. `setup-tracker` fills the placeholders
|
|
4
|
+
> and keeps **one** projection block, then deletes this blockquote.
|
|
5
|
+
>
|
|
6
|
+
> **The file's absence is the off switch.** Work Tracking is optional. A project
|
|
7
|
+
> with no `context/tracker.md` behaves exactly as it always has, and nothing in
|
|
8
|
+
> Pathfinder prompts for one. Do not ship this template's output unconfigured.
|
|
9
|
+
>
|
|
10
|
+
> **The backend-neutral model is everything between the two markers below** —
|
|
11
|
+
> from `pathfinder:model-start` down to `pathfinder:projection-boundary` — and it
|
|
12
|
+
> **must be byte-identical whichever projection is chosen.** Choosing a backend
|
|
13
|
+
> cuts below the projection boundary and nowhere else. Nothing inside the model
|
|
14
|
+
> may be *defined* in a backend's terms — an "issue number", a "label", a file
|
|
15
|
+
> path. Naming one in order to rule it out is not the same thing and is correct:
|
|
16
|
+
> "edges name keys, never tracker issue numbers" is the neutrality rule being
|
|
17
|
+
> stated, not a leak. The test is whether changing backend would change the
|
|
18
|
+
> sentence.
|
|
19
|
+
>
|
|
20
|
+
> The two paragraphs above the model marker are this project's own — the tracker
|
|
21
|
+
> it uses, and the rule that the repository wins. They are *not* claimed to be
|
|
22
|
+
> byte-identical across backends: the first one names the tracker and how an
|
|
23
|
+
> agent reaches it, so it necessarily differs.
|
|
24
|
+
|
|
25
|
+
This project tracks work in `[tracker name]`, at `[where it lives]`, reached by
|
|
26
|
+
`[how to reach it]`.
|
|
27
|
+
|
|
28
|
+
The repository is canonical. This tracker is a **one-way projection** of work
|
|
29
|
+
that already exists in `context/features/`. Never read status back out of the
|
|
30
|
+
tracker and into a spec. If the two disagree, the repository is right and the
|
|
31
|
+
tracker is stale.
|
|
32
|
+
|
|
33
|
+
<!-- pathfinder:model-start
|
|
34
|
+
Everything from here to the projection boundary is the backend-neutral model. It
|
|
35
|
+
is byte-identical in every configured project, whichever backend is chosen.
|
|
36
|
+
Nothing between the two markers may be defined in a backend's terms; naming one
|
|
37
|
+
to exclude it is correct and is not a leak.
|
|
38
|
+
-->
|
|
39
|
+
|
|
40
|
+
## What gets tracked
|
|
41
|
+
|
|
42
|
+
Only **approved feature specs**, from `to-specs` onward. Never track debate
|
|
43
|
+
notes, kickstart output, or prototypes. The one exception is a prototype that
|
|
44
|
+
gates a decision, which may be tracked as a single item phrased as the decision
|
|
45
|
+
it resolves, never as a deliverable.
|
|
46
|
+
|
|
47
|
+
## The work item
|
|
48
|
+
|
|
49
|
+
Every tracked thing is a **work item**. A work item has:
|
|
50
|
+
|
|
51
|
+
- a **key** — stable, assigned by Pathfinder, never by the tracker
|
|
52
|
+
- a **kind** — what sort of thing it is
|
|
53
|
+
- a **title** and a **body**
|
|
54
|
+
- zero or more **blocked-by** edges, naming other work items by key
|
|
55
|
+
- zero or more **tags**
|
|
56
|
+
- an ordered list of **chunks** (features only)
|
|
57
|
+
- a **parent** key (tickets only)
|
|
58
|
+
|
|
59
|
+
### Keys
|
|
60
|
+
|
|
61
|
+
A key looks like `pathfinder:<kind>/<id>`. For a feature spec, the id is the
|
|
62
|
+
spec's number: `context/features/06-docs-site-scaffold.md` is
|
|
63
|
+
`pathfinder:feature/06`.
|
|
64
|
+
|
|
65
|
+
Keys are how a work item is recognised on a later run. Record the key inside the
|
|
66
|
+
published item so it can be found again without keeping a local index. Put it in
|
|
67
|
+
a marker block that the tracker will not render to a human:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
<!-- pathfinder:work-item
|
|
71
|
+
key: pathfinder:feature/06
|
|
72
|
+
kind: feature
|
|
73
|
+
blocked-by: pathfinder:feature/03
|
|
74
|
+
tags: area:site, type:infra, agent:suitable
|
|
75
|
+
chunks-projection: checklist
|
|
76
|
+
-->
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Match on the key alone. Never match on the title — titles are edited by humans
|
|
80
|
+
and a title match will create duplicates or overwrite the wrong item.
|
|
81
|
+
|
|
82
|
+
**The title is written once, when the item is created, and is never reconciled
|
|
83
|
+
afterwards.** It is human-owned from that point on. This is a decision, not an
|
|
84
|
+
oversight, and it follows from the rule above: humans edit titles, so a
|
|
85
|
+
projection that rewrote them would overwrite that edit on every run. Renaming
|
|
86
|
+
the spec changes the pointer to it in the body, not the title.
|
|
87
|
+
|
|
88
|
+
**Prose alone is not sufficient for identity.** This marker is the one
|
|
89
|
+
machine-stable token in an otherwise prose contract. Everything else here can be
|
|
90
|
+
reworded; this cannot be removed on the grounds that the config is "just prose".
|
|
91
|
+
Without it there is no way to recognise an item on a second run, and publishing
|
|
92
|
+
stops being idempotent.
|
|
93
|
+
|
|
94
|
+
### Kinds
|
|
95
|
+
|
|
96
|
+
Two kinds are defined.
|
|
97
|
+
|
|
98
|
+
- `feature` — one approved feature spec. One branch, one review, one merge.
|
|
99
|
+
- `ticket` — an independently assignable unit of execution inside a feature,
|
|
100
|
+
carrying its own blocked-by edges so that more than one agent can work a
|
|
101
|
+
feature at once. A ticket names its feature with `parent`.
|
|
102
|
+
|
|
103
|
+
**A ticket is not a delivery chunk.** Chunks are a planning device inside a spec;
|
|
104
|
+
tickets are units of execution. They may coincide, and they routinely will not: a
|
|
105
|
+
ticket may span several chunks, and a ticket may exist that belongs to no chunk
|
|
106
|
+
at all — a prefactor, or a decision that gates the rest. Nothing in this model
|
|
107
|
+
derives one from the other, and a projection that assumed `ticket == chunk` would
|
|
108
|
+
be wrong rather than simplified.
|
|
109
|
+
|
|
110
|
+
**Do not treat a chunk as permanently equal to a checkbox either.** Chunk
|
|
111
|
+
rendering is a *projection choice* named by `chunks-projection`, not a fact about
|
|
112
|
+
the model.
|
|
113
|
+
|
|
114
|
+
Feature and ticket are the **same work item**. They carry the same fields, the
|
|
115
|
+
same marker, the same edge semantics, the same tag model, and the same
|
|
116
|
+
idempotency rule. `chunks` is simply absent on a ticket, and `parent` is absent on
|
|
117
|
+
a feature — optional fields, not different shapes. **No rule anywhere may branch
|
|
118
|
+
on `kind`.**
|
|
119
|
+
|
|
120
|
+
### Parent
|
|
121
|
+
|
|
122
|
+
A ticket names the feature it belongs to with `parent`, a key. Parentage is
|
|
123
|
+
**not** a blocking edge and must never be rendered as one: a ticket is not
|
|
124
|
+
blocked by its feature. Rendering parentage as a blocker produces a graph that
|
|
125
|
+
never unblocks.
|
|
126
|
+
|
|
127
|
+
### Blocked-by edges
|
|
128
|
+
|
|
129
|
+
Edges name **keys**, never tracker issue numbers. Resolving a key to an issue
|
|
130
|
+
number is the projection's job, and the same edge must survive being pointed at a
|
|
131
|
+
different tracker.
|
|
132
|
+
|
|
133
|
+
An edge may name a work item that is **not in the set being published**. That is
|
|
134
|
+
normal — a feature can depend on one that was tracked earlier or not at all. Do
|
|
135
|
+
not drop such an edge and do not invent an item for it. Resolve it against the
|
|
136
|
+
tracker as a whole rather than against this run:
|
|
137
|
+
|
|
138
|
+
- if the key already has an item in the tracker, render that item's identifier,
|
|
139
|
+
exactly as an in-set edge is rendered;
|
|
140
|
+
- otherwise render the key and say plainly that it has no item here.
|
|
141
|
+
|
|
142
|
+
Being outside this run is not the same as being untracked, and an edge must not
|
|
143
|
+
claim it is.
|
|
144
|
+
|
|
145
|
+
Publish in dependency order, blockers first, so an edge can reference a real
|
|
146
|
+
identifier by the time it is written.
|
|
147
|
+
|
|
148
|
+
### Tags
|
|
149
|
+
|
|
150
|
+
A tag is `namespace:value`. The namespace says what kind of statement the tag is
|
|
151
|
+
making; the value is free text.
|
|
152
|
+
|
|
153
|
+
Namespaces in use here:
|
|
154
|
+
|
|
155
|
+
- `area` — the part of the system touched, e.g. `area:site`, `area:cli`
|
|
156
|
+
- `type` — the nature of the work, e.g. `type:infra`, `type:content`
|
|
157
|
+
- `priority` — only when the project actually uses one, e.g. `priority:now`
|
|
158
|
+
- `agent` — suitability for autonomous work, e.g. `agent:suitable`,
|
|
159
|
+
`agent:needs-human`
|
|
160
|
+
|
|
161
|
+
**Tags are backend-neutral.** The list above is the whole model. How a tag
|
|
162
|
+
becomes a label, a field, or a line of text is a projection concern.
|
|
163
|
+
|
|
164
|
+
**Respect what the tracker already has.** Before introducing any tag value,
|
|
165
|
+
list the values the tracker already carries. If one already means the same
|
|
166
|
+
thing, use it and record the mapping below rather than creating a
|
|
167
|
+
near-duplicate. Never invent a taxonomy the team did not ask for, and never
|
|
168
|
+
apply a tag that is not in the mapping table.
|
|
169
|
+
|
|
170
|
+
### From spec to work item
|
|
171
|
+
|
|
172
|
+
Every field above comes from the spec, and from nowhere else:
|
|
173
|
+
|
|
174
|
+
- **key** — `pathfinder:feature/<NN>`, from the spec's number.
|
|
175
|
+
- **kind** — `feature` for an approved feature spec.
|
|
176
|
+
- **title** — the spec's own title.
|
|
177
|
+
- **blocked-by** — the specs named under `## Dependencies`, each converted to
|
|
178
|
+
its key. A dependency that is not a feature spec — a decision, an external
|
|
179
|
+
system, `None` — produces no edge.
|
|
180
|
+
- **chunks** — the entries under `## Delivery Chunks`, in spec order.
|
|
181
|
+
- **tags** — **only** the values written in the spec's optional `## Tags`
|
|
182
|
+
section.
|
|
183
|
+
|
|
184
|
+
**Tags are never inferred.** Not from the title, not from the paths a spec
|
|
185
|
+
mentions, not from which part of the system it appears to touch. A spec with no
|
|
186
|
+
`## Tags` section has no tags, and an item published with none is correct and
|
|
187
|
+
expected — most projects never use them. Guessing a tag produces a taxonomy the
|
|
188
|
+
team did not choose, applied to work they did not classify, and it will look
|
|
189
|
+
authoritative on the board.
|
|
190
|
+
|
|
191
|
+
If a spec names a tag that this config's mapping table does not carry, **stop and
|
|
192
|
+
ask**. Do not apply it, and do not quietly drop it.
|
|
193
|
+
|
|
194
|
+
### Body composition
|
|
195
|
+
|
|
196
|
+
The body is a **pure function of the spec**. The same spec must produce the same
|
|
197
|
+
body on every run. This is not tidiness: re-publishing decides what to do by
|
|
198
|
+
comparing the body it would write now against the one already there, so a body
|
|
199
|
+
that varies between runs rewrites every item forever while appearing to work.
|
|
200
|
+
|
|
201
|
+
Compose it in this order, and **omit any section whose source is absent** rather
|
|
202
|
+
than emitting it empty:
|
|
203
|
+
|
|
204
|
+
1. a pointer to the spec this item projects
|
|
205
|
+
2. the blocked-by edges
|
|
206
|
+
3. the parent, on a ticket
|
|
207
|
+
4. the delivery chunks
|
|
208
|
+
5. the statement that the repository is canonical and that nothing here is read
|
|
209
|
+
back
|
|
210
|
+
6. the marker block, last
|
|
211
|
+
|
|
212
|
+
**Never include anything derived from the run rather than the spec** — no date,
|
|
213
|
+
no timestamp, no run counter, no tally of what changed, no note of who published
|
|
214
|
+
it. Each of those differs on the next run and each would make every item look
|
|
215
|
+
modified. Never re-wrap or re-summarise text taken from the spec: copy it the
|
|
216
|
+
same way every time, or the same spec produces two different bodies.
|
|
217
|
+
|
|
218
|
+
How each of these elements *renders* is a projection concern. The order, the
|
|
219
|
+
omission rule, and the absence of run-derived content are not.
|
|
220
|
+
|
|
221
|
+
<!-- pathfinder:projection-boundary
|
|
222
|
+
This marker closes the neutral model opened by `pathfinder:model-start`.
|
|
223
|
+
Everything below is one projection. Keep exactly one of the two blocks that
|
|
224
|
+
follow, and delete this marker, the model-start marker, and the block you did
|
|
225
|
+
not keep.
|
|
226
|
+
-->
|
|
227
|
+
|
|
228
|
+
## Projection to GitHub
|
|
229
|
+
|
|
230
|
+
*Keep this block for a GitHub Issues tracker; delete the local-files block below.*
|
|
231
|
+
|
|
232
|
+
- One work item → one issue.
|
|
233
|
+
- Title → the spec's title, prefixed with its number: `06 — Docs Site Scaffold`.
|
|
234
|
+
- The **spec pointer** → the first line of the body, naming the spec's path.
|
|
235
|
+
- The **repository-is-canonical statement** → a line near the end of the body,
|
|
236
|
+
before the marker, saying that nothing here is read back and that a ticked box
|
|
237
|
+
advances no state.
|
|
238
|
+
- The marker block goes at the **end** of the issue body.
|
|
239
|
+
- `blocked-by` → a `**Blocked by**` line naming each blocker as
|
|
240
|
+
`#<number> (<key>)`. A key with no issue in this repository renders as
|
|
241
|
+
`<key> — not tracked here`; a key that has one renders as `#<number> (<key>)`
|
|
242
|
+
whether or not it is part of the current run.
|
|
243
|
+
- `parent` → a `**Parent**` line naming the feature as `#<number> (<key>)`.
|
|
244
|
+
Never render parentage as a blocking edge.
|
|
245
|
+
- `chunks` under `chunks-projection: checklist` → a `## Delivery chunks` section
|
|
246
|
+
of `- [ ]` items in spec order. **A checked box means nothing to Pathfinder.**
|
|
247
|
+
The repository is canonical; a human ticking a box does not advance any state
|
|
248
|
+
and must never be read back.
|
|
249
|
+
- Tags → labels, via this mapping. Create a label only if nothing equivalent
|
|
250
|
+
exists. Replace the rows below with this project's own tags and the labels the
|
|
251
|
+
repository already carries.
|
|
252
|
+
|
|
253
|
+
| Tag | GitHub label | Colour |
|
|
254
|
+
|---|---|---|
|
|
255
|
+
| `area:site` | `area:site` | `1d76db` |
|
|
256
|
+
| `area:cli` | `area:cli` | `1d76db` |
|
|
257
|
+
| `type:infra` | `type:infra` | `5319e7` |
|
|
258
|
+
| `type:content` | `documentation` *(pre-existing — reused, not duplicated)* | `0075ca` |
|
|
259
|
+
| `agent:suitable` | `agent:suitable` | `0e8a16` |
|
|
260
|
+
| `agent:needs-human` | `agent:needs-human` | `d93f0b` |
|
|
261
|
+
|
|
262
|
+
### Publishing, and re-publishing
|
|
263
|
+
|
|
264
|
+
**Ask the human before the first write to this tracker in a session.** Creating
|
|
265
|
+
issues on a shared repository is outward-facing and is not covered by ordinary
|
|
266
|
+
file-edit approval.
|
|
267
|
+
|
|
268
|
+
Publishing is **idempotent**. Re-running must be safe and must be provably inert
|
|
269
|
+
when nothing changed:
|
|
270
|
+
|
|
271
|
+
1. Read every existing issue in the repository, open and closed, and index them
|
|
272
|
+
by the key in their marker block.
|
|
273
|
+
2. For each work item, if no issue carries its key, create one.
|
|
274
|
+
3. If an issue carries its key, compare the rendered body and the label set to
|
|
275
|
+
what would be published now. **If they are identical, do nothing at all** —
|
|
276
|
+
no edit, no comment, no label call. An unchanged item must produce zero
|
|
277
|
+
writes, not a write that happens to be a no-op.
|
|
278
|
+
|
|
279
|
+
**Compare normalized, never raw bytes.** A tracker is not obliged to hand a
|
|
280
|
+
body back exactly as it was sent, and APIs differ in whether they adjust
|
|
281
|
+
trailing whitespace. Where that happens, a naive byte comparison reports every
|
|
282
|
+
issue as changed on every run and rewrites all of them forever — which looks
|
|
283
|
+
like working sync and is not. Before comparing, strip trailing whitespace from
|
|
284
|
+
each line and collapse trailing blank lines at end of body, on **both** sides.
|
|
285
|
+
This costs nothing when the round-trip is exact, and is the difference between
|
|
286
|
+
inert and catastrophic when it is not. Compare label sets as sets, not as
|
|
287
|
+
ordered lists — the tracker does not preserve the order they were applied.
|
|
288
|
+
4. If they differ, edit that issue in place. Never close and recreate.
|
|
289
|
+
5. Never close an issue, never reopen one, and never touch an issue whose key is
|
|
290
|
+
absent from the current set — it belongs to work outside this run.
|
|
291
|
+
|
|
292
|
+
Report what was created, what was edited, and what was left alone.
|
|
293
|
+
|
|
294
|
+
## Projection to local files
|
|
295
|
+
|
|
296
|
+
*Keep this block for a local Markdown tracker; delete the GitHub block above.*
|
|
297
|
+
|
|
298
|
+
- One work item → one file, `.work/<NN>-<slug>.md`. On first publish the files
|
|
299
|
+
are numbered from `01` in dependency order, so blockers sort first.
|
|
300
|
+
|
|
301
|
+
**`<NN>` is presentation and ordering only. It is never identity** — a file is
|
|
302
|
+
recognised by the key inside it, and nothing may match on the prefix.
|
|
303
|
+
|
|
304
|
+
A new file takes the **next unused prefix**, not the position it would occupy
|
|
305
|
+
in dependency order. Existing files are **never renumbered**: renaming a file
|
|
306
|
+
is deleting one and creating another, and re-publishing must never do that —
|
|
307
|
+
it would rewrite unrelated files every time a blocker was inserted. So after a
|
|
308
|
+
dependency change the prefixes no longer sort into dependency order, and that
|
|
309
|
+
is expected. Read the current order from the `**Blocked by**` lines, which are
|
|
310
|
+
reconciled. The prefixes are not.
|
|
311
|
+
- Title → an `# ` heading, prefixed with its number: `06 — Docs Site Scaffold`.
|
|
312
|
+
- The **spec pointer** → the first line of the body, naming the spec's path.
|
|
313
|
+
- The **repository-is-canonical statement** → a line near the end of the file,
|
|
314
|
+
before the marker, saying that nothing here is read back and that a ticked box
|
|
315
|
+
advances no state.
|
|
316
|
+
- The marker block goes at the **end** of the file.
|
|
317
|
+
- `blocked-by` → a `**Blocked by**` line naming each blocker as
|
|
318
|
+
`<file> (<key>)`. A key with no file under `.work/` renders as
|
|
319
|
+
`<key> — not tracked here`; a key that has one renders as `<file> (<key>)`
|
|
320
|
+
whether or not it is part of the current run.
|
|
321
|
+
- `parent` → a `**Parent**` line naming the feature as `<file> (<key>)`.
|
|
322
|
+
Never render parentage as a blocking edge.
|
|
323
|
+
- `chunks` under `chunks-projection: checklist` → a `## Delivery chunks` section
|
|
324
|
+
of `- [ ]` items in spec order. **A checked box means nothing to Pathfinder.**
|
|
325
|
+
The repository is canonical; a human ticking a box does not advance any state
|
|
326
|
+
and must never be read back.
|
|
327
|
+
- Tags → a `**Tags**` line listing them verbatim, comma-separated, in the order
|
|
328
|
+
given. There is no label object to create, so the mapping is the identity
|
|
329
|
+
mapping and no colour applies. Replace the rows below with this project's own
|
|
330
|
+
tags.
|
|
331
|
+
|
|
332
|
+
| Tag | Local rendering |
|
|
333
|
+
|---|---|
|
|
334
|
+
| `area:site` | `area:site` |
|
|
335
|
+
| `area:cli` | `area:cli` |
|
|
336
|
+
| `type:infra` | `type:infra` |
|
|
337
|
+
| `type:content` | `type:content` |
|
|
338
|
+
| `agent:suitable` | `agent:suitable` |
|
|
339
|
+
| `agent:needs-human` | `agent:needs-human` |
|
|
340
|
+
|
|
341
|
+
### Publishing, and re-publishing
|
|
342
|
+
|
|
343
|
+
No approval is required to write under `.work/` — it is an ordinary file edit in
|
|
344
|
+
this repository and reaches nothing outside it.
|
|
345
|
+
|
|
346
|
+
Publishing is **idempotent**. Re-running must be safe and must be provably inert
|
|
347
|
+
when nothing changed:
|
|
348
|
+
|
|
349
|
+
1. Read every existing file under `.work/` and index them by the key in their
|
|
350
|
+
marker block.
|
|
351
|
+
2. For each work item, if no file carries its key, create one.
|
|
352
|
+
3. If a file carries its key, compare its full contents to what would be written
|
|
353
|
+
now. **If they are identical, do nothing at all** — do not rewrite the file
|
|
354
|
+
with the same bytes. An unchanged item must leave its mtime untouched.
|
|
355
|
+
4. If they differ, rewrite that file in place. Never delete and recreate.
|
|
356
|
+
5. Never delete a file, and never touch a file whose key is absent from the
|
|
357
|
+
current set — it belongs to work outside this run.
|
|
358
|
+
|
|
359
|
+
Report what was created, what was edited, and what was left alone.
|