@erclx/aitk 0.57.0 → 0.59.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.
@@ -0,0 +1,145 @@
1
+ ---
2
+ title: Plan reference
3
+ description: Filename and slug, required sections, the suggested-and-answer contract, and the lifecycle from the live folder to the archive
4
+ ---
5
+
6
+ # Plan reference
7
+
8
+ Applies to a feature plan at `.claude/plans/feature-<slug>.md`. One file holds one concern, written before implementation starts and read by whatever executes it, so it has to carry the scope without the conversation that produced it.
9
+
10
+ The folder is gitignored and unbacked. Nothing recovers a deleted plan, which is why the archive step below is a move rather than a cleanup.
11
+
12
+ ## Scope
13
+
14
+ Governs a feature plan under `.claude/plans/feature-<slug>.md`: the filename, the required sections, what each holds, the suggested-and-answer contract, and the lifecycle from the live folder to the archive.
15
+
16
+ Does not govern:
17
+
18
+ - One question measured in depth before anyone can plan against it: `groundwork.md`
19
+ - A dump of many findings filed by domain, each carrying its own verdict: `intake.md`
20
+ - The task file a plan is linked from, and the origin line pointing back at it: `tasks.md`
21
+ - The transform from a branch name to a slug: `slug.md`
22
+ - Voice and word choice: `prose.md`
23
+ - Headings, punctuation, and file references: `markdown.md`
24
+ - When a plan is written at all, and whether a short one goes to a file or to the conversation, which belong to the surface driving it
25
+
26
+ ## What a working plan looks like
27
+
28
+ A plan works when a session holding none of the conversation that produced it can execute from the file alone:
29
+
30
+ - What is being built, and which files does it change?
31
+ - Which decisions are already settled, and which are still open?
32
+ - For each open decision, what happens when nobody answers it?
33
+ - What is likely to go wrong, and where does the work collide with something already in flight?
34
+
35
+ A plan failing these is non-conforming even when it satisfies every shape rule below.
36
+
37
+ ## Filename and slug
38
+
39
+ - Name the file `feature-<slug>.md`, with `<slug>` two to four kebab-case words naming the concern.
40
+ - Write one concern per file. A request spanning two independent concerns takes two plans rather than one bundling both, since a bundled plan cannot be executed by two sessions or abandoned by half.
41
+ - Derive the slug from the concern rather than from a branch, because the plan is written before the branch exists.
42
+ - Give the branch that executes the plan the same slug. A later surface finds the plan from the branch name and finds nothing when the two spellings differ.
43
+
44
+ A plan carries no frontmatter. Its filename is the whole of its identity, so a folder of plans is read by name rather than by a generated catalog.
45
+
46
+ ## Sections
47
+
48
+ The document opens with `# Feature: <short title>` and one paragraph stating what is being built and why now. The sections below follow in this order.
49
+
50
+ | Section | Holds | Required |
51
+ | --------------------- | ------------------------------------------------------------------------- | ------------- |
52
+ | `## Summary` | three to five one-line bullets: the goal, the deliverables, the trade-off | Always |
53
+ | `**Constraints:**` | durable rules the work must respect | When supplied |
54
+ | `**Files to touch:**` | each file with a one-line reason | Always |
55
+ | `**Risks:**` | conflicts, coupling, and the tricky spots | Always |
56
+ | `**Questions:**` | numbered open decisions, each with a suggestion and an answer slot | Always |
57
+
58
+ - Write each marker as the table gives it. `Summary` opens the prose a reader scans, so it takes an H2, and the four that follow are labels over lists rather than sections of prose.
59
+ - A section written in the other spelling is still that section. `## Risks` and `**Risks:**` name one thing, and a plan carrying either has stated its risks, so neither reads as an omission. Write the table's form in a new plan and leave an existing plan's spelling alone.
60
+ - Write `None identified.` under a required section with nothing to report rather than dropping the marker. A dropped section and an unconsidered one read identically.
61
+ - Aim `## Summary` at a person scanning the plan, not at the session executing it. The other sections carry what execution needs.
62
+ - Give every `**Files to touch:**` entry a backticked path and something said about it. A bare path states scope and not intent, and the reason is what an executing session checks its edit against. Lead with the path or lead with a label carrying the path, whichever reads better for the entry.
63
+ - State every count and every claim about the tree as measured during the pass that wrote the plan. A figure carried in from a summary or an earlier session is the most common way a plan ships the wrong scope.
64
+ - Prefer a short plan over a padded one. A section filled to look thorough costs the reader the same attention as one that matters.
65
+
66
+ ### Constraints
67
+
68
+ A constraint naming a surface to leave alone forbids two different acts, and it says which. A constraint carrying only the surface leaves the executing session to guess.
69
+
70
+ - Forbid conforming that surface to whatever shape the change introduces. This is what a scope constraint means, and it keeps the branch from growing a second concern.
71
+ - Never forbid retargeting a pointer the change breaks. A rename, a split, or a deletion that leaves a citation behind ships a dangling reference, so repairing it is required work rather than scope creep.
72
+ - Decide both acts for every surface the constraint names. Carving the distinction out for one file and leaving its siblings under the bare wording ships one correct call beside one broken reference.
73
+
74
+ ### Risks
75
+
76
+ - Name the collision rather than the category. A risk a reader cannot act on is padding.
77
+ - Where the work establishes a resource with more than one consumer, list the consumers and mark each one read or write. A policy stated over that resource has to hold for the writers and not only for the consumer that prompted it.
78
+
79
+ ## The suggested-and-answer contract
80
+
81
+ Every question carries a `- Suggested:` line and an empty `- Answer:` slot below it.
82
+
83
+ ```markdown
84
+ 1. <question>
85
+ - Suggested: <pick>, <reason or tradeoff>
86
+ - Answer:
87
+ ```
88
+
89
+ - A blank `- Answer:` means accept the suggestion at execution time. That default is what makes the plan decision-ready in one pass, with no separate round to collect answers.
90
+ - Never ship a question without a suggestion. A bare question defers the judgment the plan exists to supply, and it arrives at the executing session as a stop.
91
+ - State the pick in one line with its reason or its main tradeoff. List an alternative only where it changes the pick.
92
+ - Write `- Suggested: needs your call, <why>` where the answer turns on preference rather than on a technical default. Fabricating a default there hides an open question behind an accepted answer.
93
+ - Never fill an `- Answer:` slot on behalf of the person who owns it. Recording the pick as the suggestion is what the suggestion line is for.
94
+ - Answer in place when a question is settled in conversation, so the file and the decision do not disagree.
95
+
96
+ This contract inverts the one an intake folder keeps, where an empty slot means unread and acceptance is typed out. A plan is written and read in one sitting with every question already surfaced, so silence is a usable default here and is not one there. Both files state the inversion, since a contract read on only one side of a boundary is the one that gets applied to the wrong document.
97
+
98
+ ## Lifecycle
99
+
100
+ - Write the plan before implementation starts, and treat it as the scope of the run that executes it.
101
+ - Keep every plan at one root. A plan copied into each parallel working tree forks, and the copies answer the same question differently.
102
+ - Amend the plan in place when a decision changes mid-flight. Do not append a second passage narrating the change, which leaves a reader to work out which of two answers is current.
103
+ - Move the plan to `.claude/plans-archive/` when the work it describes ships. Never delete it, because the plan is where the rejected alternative is written down and nothing else records it.
104
+ - Write the plan in the same session that opens the task it serves. The session executing it later inherits reasoning it would otherwise re-derive.
105
+
106
+ ## Anti-patterns
107
+
108
+ - **The plan written before the measuring.** A subject that has to be measured before anyone can plan against it belongs in a measurement track, and every plan that skipped that step had to be superseded.
109
+ - **The bundled plan.** Two concerns under one slug cannot be split later without rewriting both halves.
110
+ - **The question with no suggestion.** It reads as thoroughness and lands as a blocked run.
111
+ - **The answer filled in by the author.** A slot holding the writer's own pick destroys the only signal that anyone else agreed.
112
+ - **The count carried in.** A figure quoted from an earlier session survives the change that invalidated it, and the scope built on it is quietly wrong.
113
+ - **The plan deleted on ship.** The considered-and-dropped reasoning goes with it, and the next session re-proposes what this one rejected.
114
+
115
+ ## Template
116
+
117
+ ```markdown
118
+ # Feature: <short title>
119
+
120
+ <One paragraph on what is being built and why now.>
121
+
122
+ ## Summary
123
+
124
+ - <one-line bullet covering the goal>
125
+ - <one-line bullet covering the main deliverables>
126
+ - <one-line bullet covering the key decision or trade-off>
127
+
128
+ **Constraints:**
129
+
130
+ - <durable rule the work must respect>
131
+
132
+ **Files to touch:**
133
+
134
+ - `<path/to/file>`: <reason>
135
+
136
+ **Risks:**
137
+
138
+ - <conflict, coupling, or tricky spot>
139
+
140
+ **Questions:**
141
+
142
+ 1. <question>
143
+ - Suggested: <pick>, <reason or tradeoff>
144
+ - Answer:
145
+ ```
package/standards/rule.md CHANGED
@@ -33,6 +33,15 @@ Write both when both apply. A rule stating the directive and a skill stating how
33
33
  - Subdirectories group by domain: `core/`, `lang/`, `framework/`, `lib/`, `ui/`, `claude/`
34
34
  - `<n>` is a number in the subdirectory's band and `<slug>` is a one-to-three-word kebab topic
35
35
  - Scaffold a rule with a number that collides with neither the project's rules nor any installed shared rule set
36
+ - Give every rule a numeric prefix. A bare-word filename reads as a folder name where a stack names its rules, so a rule without one is unreachable from a stack entry.
37
+
38
+ ## Two sources numbering into one folder
39
+
40
+ A shared rule set and a project's own rules land in the same installed folder and draw from the same band, so the two need a division or they collide. Divide the band by source rather than by topic: one source takes the top of each band and the other takes the gaps between the tens. A rule set that ships to targets should take the tens, since it is the source a project cannot renumber.
41
+
42
+ The collision this prevents is silent. Two rules that resolve to the same `<n>-<slug>` path leave one file in the installed folder, and neither the install nor the session that reads it reports which source lost. Nothing checks the division, so it holds only while both sources follow it.
43
+
44
+ State the division where the rule sources are described, not in the rules themselves. A rule states its own topic, and a numbering convention spanning two sources belongs to whatever documents the pair.
36
45
 
37
46
  ## Frontmatter
38
47
 
@@ -15,6 +15,7 @@ Governs the task board under `.claude/tasks/`: folder layout, filenames, frontma
15
15
 
16
16
  Does not govern:
17
17
 
18
+ - The plan file a task cites, its sections, and its answer contract: `plan.md`
18
19
  - Phase-label format and which surfaces a label may appear on: `versioning.md`
19
20
  - Sequencing across versions and why the order is what it is: `roadmap.md`
20
21
  - Architectural reasoning that outlives a task: `architecture.md`
@@ -1,234 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -e
3
- set -o pipefail
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- PROJECT_ROOT="${PROJECT_ROOT:-$(dirname "$(dirname "$SCRIPT_DIR")")}"
7
-
8
- source "$PROJECT_ROOT/scripts/lib/ui.sh"
9
-
10
- STACKS_DIR="$PROJECT_ROOT/governance/stacks"
11
- RULES_DIR="$PROJECT_ROOT/governance/rules"
12
-
13
- show_help() {
14
- echo -e "${GREY}┌${NC}"
15
- echo -e "${GREY}├${NC} ${WHITE}Usage:${NC} aitk gov list [options]"
16
- echo -e "${GREY}│${NC}"
17
- echo -e "${GREY}│${NC} ${WHITE}Options:${NC}"
18
- echo -e "${GREY}│${NC} --stacks ${GREY}# Only list stacks${NC}"
19
- echo -e "${GREY}│${NC} --rules ${GREY}# Only list rules${NC}"
20
- echo -e "${GREY}│${NC} --json ${GREY}# Emit machine-readable JSON${NC}"
21
- echo -e "${GREY}│${NC} -h, --help ${GREY}# Show this help message${NC}"
22
- echo -e "${GREY}└${NC}"
23
- exit 0
24
- }
25
-
26
- read_frontmatter_field() {
27
- local file="$1"
28
- local field="$2"
29
- awk -v f="$field" '
30
- BEGIN { fm = 0 }
31
- /^---$/ { fm++; if (fm > 1) exit; next }
32
- fm == 1 {
33
- if (match($0, "^" f ":")) {
34
- val = substr($0, RLENGTH + 1)
35
- sub(/^[[:space:]]+/, "", val)
36
- sub(/^[\x27"]/, "", val)
37
- sub(/[\x27"]$/, "", val)
38
- print val
39
- exit
40
- }
41
- }
42
- ' "$file"
43
- }
44
-
45
- read_frontmatter_paths() {
46
- local file="$1"
47
- awk '
48
- BEGIN { fm = 0; in_paths = 0 }
49
- /^---$/ { fm++; if (fm > 1) exit; next }
50
- fm == 1 {
51
- if (in_paths) {
52
- if (match($0, /^[[:space:]]*-[[:space:]]+/)) {
53
- val = substr($0, RLENGTH + 1)
54
- sub(/^[\x27"]/, "", val)
55
- sub(/[\x27"]$/, "", val)
56
- print val
57
- next
58
- }
59
- in_paths = 0
60
- }
61
- if ($0 == "paths:") { in_paths = 1 }
62
- }
63
- ' "$file"
64
- }
65
-
66
- rule_domain() {
67
- local file="$1"
68
- local rel="${file#"$RULES_DIR"/}"
69
- echo "${rel%%/*}"
70
- }
71
-
72
- stack_rules_array() {
73
- local toml="$1"
74
- grep -oE '"[0-9]{3}-[a-z0-9-]+"' "$toml" | sed 's/"//g'
75
- }
76
-
77
- json_escape() {
78
- local s="$1"
79
- s="${s//\\/\\\\}"
80
- s="${s//\"/\\\"}"
81
- printf '%s' "$s"
82
- }
83
-
84
- list_stacks_text() {
85
- log_step "Stacks"
86
- local toml
87
- for toml in "$STACKS_DIR"/*.toml; do
88
- local name
89
- name=$(basename "$toml" .toml)
90
- local extends
91
- extends=$(grep '^extends' "$toml" | cut -d'"' -f2)
92
- local rule_count
93
- rule_count=$(stack_rules_array "$toml" | wc -l)
94
- if [ -n "$extends" ]; then
95
- log_info "$name (extends: $extends, $rule_count rules)"
96
- else
97
- log_info "$name ($rule_count rules)"
98
- fi
99
- done
100
- }
101
-
102
- list_rules_text() {
103
- log_step "Rules"
104
- local file
105
- while IFS= read -r file; do
106
- local name
107
- name=$(basename "$file" .md)
108
- local domain
109
- domain=$(rule_domain "$file")
110
- local desc
111
- desc=$(read_frontmatter_field "$file" "description")
112
- log_info "$name [$domain] $desc"
113
- done < <(find "$RULES_DIR" -type f -name "*.md" | sort)
114
- }
115
-
116
- list_stacks_json() {
117
- local first=1
118
- local toml
119
- printf '['
120
- for toml in "$STACKS_DIR"/*.toml; do
121
- local name
122
- name=$(basename "$toml" .toml)
123
- local extends
124
- extends=$(grep '^extends' "$toml" | cut -d'"' -f2)
125
- local rules_json="["
126
- local first_rule=1
127
- local rule
128
- while IFS= read -r rule; do
129
- [ -z "$rule" ] && continue
130
- if [ "$first_rule" -eq 0 ]; then
131
- rules_json+=","
132
- fi
133
- rules_json+="\"$rule\""
134
- first_rule=0
135
- done < <(stack_rules_array "$toml")
136
- rules_json+="]"
137
- if [ "$first" -eq 0 ]; then
138
- printf ','
139
- fi
140
- if [ -n "$extends" ]; then
141
- printf '{"name":"%s","extends":"%s","rules":%s}' "$name" "$extends" "$rules_json"
142
- else
143
- printf '{"name":"%s","extends":null,"rules":%s}' "$name" "$rules_json"
144
- fi
145
- first=0
146
- done
147
- printf ']'
148
- }
149
-
150
- list_rules_json() {
151
- local first=1
152
- local file
153
- printf '['
154
- while IFS= read -r file; do
155
- local name
156
- name=$(basename "$file" .md)
157
- local domain
158
- domain=$(rule_domain "$file")
159
- local desc
160
- desc=$(read_frontmatter_field "$file" "description")
161
-
162
- local paths_json="null"
163
- local paths_collected=()
164
- while IFS= read -r p; do
165
- [ -n "$p" ] && paths_collected+=("$p")
166
- done < <(read_frontmatter_paths "$file")
167
- if [ "${#paths_collected[@]}" -gt 0 ]; then
168
- paths_json="["
169
- local first_p=1
170
- local p
171
- for p in "${paths_collected[@]}"; do
172
- [ "$first_p" -eq 0 ] && paths_json+=","
173
- paths_json+="\"$(json_escape "$p")\""
174
- first_p=0
175
- done
176
- paths_json+="]"
177
- fi
178
-
179
- if [ "$first" -eq 0 ]; then
180
- printf ','
181
- fi
182
- printf '{"name":"%s","domain":"%s","description":"%s","paths":%s}' \
183
- "$name" "$domain" "$(json_escape "$desc")" "$paths_json"
184
- first=0
185
- done < <(find "$RULES_DIR" -type f -name "*.md" | sort)
186
- printf ']'
187
- }
188
-
189
- main() {
190
- local show_stacks=1
191
- local show_rules=1
192
- local json=0
193
-
194
- while [[ $# -gt 0 ]]; do
195
- case "$1" in
196
- -h | --help) show_help ;;
197
- --stacks)
198
- show_rules=0
199
- shift
200
- ;;
201
- --rules)
202
- show_stacks=0
203
- shift
204
- ;;
205
- --json)
206
- json=1
207
- shift
208
- ;;
209
- *) log_error "Unknown option: $1" ;;
210
- esac
211
- done
212
-
213
- trap close_timeline EXIT
214
-
215
- if [ "$json" -eq 1 ]; then
216
- printf '{'
217
- if [ "$show_stacks" -eq 1 ]; then
218
- printf '"stacks":'
219
- list_stacks_json
220
- [ "$show_rules" -eq 1 ] && printf ','
221
- fi
222
- if [ "$show_rules" -eq 1 ]; then
223
- printf '"rules":'
224
- list_rules_json
225
- fi
226
- printf '}\n'
227
- exit 0
228
- fi
229
-
230
- [ "$show_stacks" -eq 1 ] && list_stacks_text
231
- [ "$show_rules" -eq 1 ] && list_rules_text
232
- }
233
-
234
- main "$@"