@bompus/house-rules 0.0.0-stage → 0.13.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.
Files changed (236) hide show
  1. package/CODE_OF_CONDUCT.md +83 -0
  2. package/CONTRIBUTING.md +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +378 -2
  5. package/THIRD_PARTY_NOTICES.md +188 -0
  6. package/compose.mjs +125 -0
  7. package/composition.mjs +361 -0
  8. package/config-view.mjs +209 -0
  9. package/config.mjs +381 -0
  10. package/docs/assets/banner-dark.png +0 -0
  11. package/docs/assets/banner-light.png +0 -0
  12. package/docs/assets/overview.png +0 -0
  13. package/docs/configuration.md +269 -0
  14. package/docs/skill-names.md +50 -0
  15. package/examples/person/house-rules.json +15 -0
  16. package/examples/person/rules/10-tooling.md +8 -0
  17. package/examples/person/rules/20-reporting.md +9 -0
  18. package/examples/project/AGENTS.md +18 -0
  19. package/package.json +42 -4
  20. package/rule-references.mjs +91 -0
  21. package/rules/core.md +340 -0
  22. package/rules/modifiers/backlog-outline.md +25 -0
  23. package/rules/modifiers/backlog-visual.md +16 -0
  24. package/rules/modifiers/coded-offers.md +70 -0
  25. package/rules/modifiers/cross-session-relay.md +23 -0
  26. package/rules/modifiers/effort-estimates.md +41 -0
  27. package/rules/modifiers/land-when-done.md +12 -0
  28. package/rules/modifiers/low-quota-handoff.md +20 -0
  29. package/rules/modifiers/model-default-questions.md +33 -0
  30. package/rules/modifiers/multi-agent.md +38 -0
  31. package/rules/modifiers/no-attribution.md +16 -0
  32. package/rules/modifiers/periodic-updates.md +25 -0
  33. package/rules/modifiers/plan-files.md +82 -0
  34. package/rules/modifiers/question-cards.md +48 -0
  35. package/rules/modifiers/release-batching.md +15 -0
  36. package/rules/modifiers/scratch-on-disk.md +15 -0
  37. package/rules/modifiers/shared-host-load.md +19 -0
  38. package/rules/modifiers/solo-operator.md +13 -0
  39. package/rules/modifiers/squash-landing.md +22 -0
  40. package/rules/modifiers/upstream-contributions.md +45 -0
  41. package/rules/modifiers/web-image-formats.md +35 -0
  42. package/rules/references/backlog-view.md +154 -0
  43. package/rules/references/github-actions.md +45 -0
  44. package/rules/references/landing.md +39 -0
  45. package/rules/references/multi-agent.md +51 -0
  46. package/rules/references/release-batching.md +66 -0
  47. package/rules/references/squash-landing.md +50 -0
  48. package/rules/references/thread-visuals.md +45 -0
  49. package/setup.mjs +445 -0
  50. package/skills/hr-agent-guidance-audit/LICENSE +21 -0
  51. package/skills/hr-agent-guidance-audit/SKILL.md +91 -0
  52. package/skills/hr-agent-guidance-audit/agents/openai.yaml +2 -0
  53. package/skills/hr-agent-guidance-audit/references/prune-workflow.md +72 -0
  54. package/skills/hr-agent-guidance-audit/references/records-and-lessons.md +60 -0
  55. package/skills/hr-agent-guidance-audit/references/retirement-verdicts.md +49 -0
  56. package/skills/hr-agent-guidance-refresh/LICENSE +21 -0
  57. package/skills/hr-agent-guidance-refresh/SKILL.md +36 -0
  58. package/skills/hr-agent-guidance-refresh/agents/openai.yaml +2 -0
  59. package/skills/hr-agent-guidance-refresh/references/verification.md +47 -0
  60. package/skills/hr-api-exposure-check/SKILL.md +159 -0
  61. package/skills/hr-api-exposure-check/agents/openai.yaml +3 -0
  62. package/skills/hr-audit-choices/SKILL.md +67 -0
  63. package/skills/hr-audit-choices/agents/openai.yaml +2 -0
  64. package/skills/hr-benchmarking/NOTICE.md +36 -0
  65. package/skills/hr-benchmarking/SKILL.md +279 -0
  66. package/skills/hr-benchmarking/agents/openai.yaml +2 -0
  67. package/skills/hr-benchmarking/references/javascript.md +130 -0
  68. package/skills/hr-benchmarking/references/tools.md +165 -0
  69. package/skills/hr-benchmarking/scripts/process-attribution.ps1 +20 -0
  70. package/skills/hr-benchmarking/scripts/process-attribution.py +107 -0
  71. package/skills/hr-better-accessibility/LICENSE +22 -0
  72. package/skills/hr-better-accessibility/NOTICE.md +46 -0
  73. package/skills/hr-better-accessibility/SKILL.md +119 -0
  74. package/skills/hr-better-accessibility/agents/openai.yaml +3 -0
  75. package/skills/hr-better-accessibility/focus-and-keyboard.md +130 -0
  76. package/skills/hr-better-accessibility/forms.md +82 -0
  77. package/skills/hr-better-accessibility/hit-areas.md +98 -0
  78. package/skills/hr-better-accessibility/motion-and-zoom.md +81 -0
  79. package/skills/hr-better-accessibility/screen-readers.md +102 -0
  80. package/skills/hr-better-accessibility/semantics-and-aria.md +84 -0
  81. package/skills/hr-better-colors/LICENSE +21 -0
  82. package/skills/hr-better-colors/NOTICE.md +37 -0
  83. package/skills/hr-better-colors/SKILL.md +114 -0
  84. package/skills/hr-better-colors/agents/openai.yaml +3 -0
  85. package/skills/hr-better-colors/color-formats.md +90 -0
  86. package/skills/hr-better-colors/color-usage.md +140 -0
  87. package/skills/hr-better-colors/contrast.md +80 -0
  88. package/skills/hr-better-colors/palette-generation.md +104 -0
  89. package/skills/hr-better-colors/palette-structure.md +76 -0
  90. package/skills/hr-better-colors/token-naming.md +97 -0
  91. package/skills/hr-better-layout/LICENSE +22 -0
  92. package/skills/hr-better-layout/NOTICE.md +48 -0
  93. package/skills/hr-better-layout/SKILL.md +92 -0
  94. package/skills/hr-better-layout/agents/openai.yaml +3 -0
  95. package/skills/hr-better-layout/grouping-and-alignment.md +144 -0
  96. package/skills/hr-better-layout/spacing-and-adaptivity.md +215 -0
  97. package/skills/hr-better-typography/LICENSE +22 -0
  98. package/skills/hr-better-typography/NOTICE.md +46 -0
  99. package/skills/hr-better-typography/SKILL.md +172 -0
  100. package/skills/hr-better-typography/agents/openai.yaml +3 -0
  101. package/skills/hr-better-typography/choosing-fonts.md +69 -0
  102. package/skills/hr-better-typography/css-cheat-sheet.md +65 -0
  103. package/skills/hr-better-typography/details-and-accessibility.md +119 -0
  104. package/skills/hr-better-typography/spacing-and-sizing.md +131 -0
  105. package/skills/hr-better-typography/variable-fonts-and-opentype.md +105 -0
  106. package/skills/hr-better-typography/wrapping-and-punctuation.md +57 -0
  107. package/skills/hr-better-writing/LICENSE +22 -0
  108. package/skills/hr-better-writing/NOTICE.md +46 -0
  109. package/skills/hr-better-writing/SKILL.md +122 -0
  110. package/skills/hr-better-writing/agents/openai.yaml +3 -0
  111. package/skills/hr-code-review/LICENSE +21 -0
  112. package/skills/hr-code-review/NOTICE.md +26 -0
  113. package/skills/hr-code-review/SKILL.md +163 -0
  114. package/skills/hr-code-review/agents/openai.yaml +3 -0
  115. package/skills/hr-code-review/references/acp-client.md +43 -0
  116. package/skills/hr-code-review/references/evidence.md +57 -0
  117. package/skills/hr-code-review/references/impact.md +103 -0
  118. package/skills/hr-code-review/references/panel-adjudication.md +58 -0
  119. package/skills/hr-code-review/references/panel-plan.md +61 -0
  120. package/skills/hr-code-review/references/panel-recommendations.json +105 -0
  121. package/skills/hr-code-review/references/panel-recommendations.md +46 -0
  122. package/skills/hr-code-review/references/panel-setup.md +54 -0
  123. package/skills/hr-code-review/references/reviewer-role.md +31 -0
  124. package/skills/hr-code-review/scripts/acp-panel-client.mjs +299 -0
  125. package/skills/hr-code-review/scripts/check-receipts.mjs +263 -0
  126. package/skills/hr-code-review/scripts/panel-plan.mjs +69 -0
  127. package/skills/hr-code-review/scripts/panel-preferences.mjs +220 -0
  128. package/skills/hr-design-exploration/SKILL.md +105 -0
  129. package/skills/hr-design-exploration/agents/openai.yaml +4 -0
  130. package/skills/hr-diagnosing-bugs/NOTICE.md +45 -0
  131. package/skills/hr-diagnosing-bugs/SKILL.md +108 -0
  132. package/skills/hr-diagnosing-bugs/agents/openai.yaml +3 -0
  133. package/skills/hr-diagnosing-bugs/references/reporting.md +97 -0
  134. package/skills/hr-diagnosing-bugs/scripts/check-pr-offer.mjs +47 -0
  135. package/skills/hr-explain-code/NOTICE.md +37 -0
  136. package/skills/hr-explain-code/SKILL.md +110 -0
  137. package/skills/hr-explain-code/agents/openai.yaml +5 -0
  138. package/skills/hr-explain-code/references/helper-brief.md +39 -0
  139. package/skills/hr-extract-shared-steps/SKILL.md +134 -0
  140. package/skills/hr-extract-shared-steps/agents/openai.yaml +3 -0
  141. package/skills/hr-forgotten-work-audit/SKILL.md +130 -0
  142. package/skills/hr-forgotten-work-audit/references/brief-template.md +56 -0
  143. package/skills/hr-forgotten-work-audit/references/result-format.md +46 -0
  144. package/skills/hr-handoff/LICENSE +21 -0
  145. package/skills/hr-handoff/NOTICE.md +29 -0
  146. package/skills/hr-handoff/SKILL.md +114 -0
  147. package/skills/hr-handoff/agents/openai.yaml +5 -0
  148. package/skills/hr-handoff/assets/ledger.example.json +10 -0
  149. package/skills/hr-handoff/assets/receipt.example.json +76 -0
  150. package/skills/hr-handoff/assets/source.example.json +20 -0
  151. package/skills/hr-handoff/references/reconciliation.md +124 -0
  152. package/skills/hr-handoff/references/successor-thread.md +76 -0
  153. package/skills/hr-handoff/scripts/check-reconciliation.mjs +324 -0
  154. package/skills/hr-house-rules-setup/SKILL.md +114 -0
  155. package/skills/hr-house-rules-setup/agents/openai.yaml +5 -0
  156. package/skills/hr-issue-tracker-setup/SKILL.md +49 -0
  157. package/skills/hr-issue-tracker-setup/agents/openai.yaml +5 -0
  158. package/skills/hr-lean-plan/SKILL.md +146 -0
  159. package/skills/hr-lean-plan/agents/openai.yaml +5 -0
  160. package/skills/hr-maintainability-review/SKILL.md +186 -0
  161. package/skills/hr-maintainability-review/agents/openai.yaml +5 -0
  162. package/skills/hr-manual-qa/NOTICE.md +36 -0
  163. package/skills/hr-manual-qa/SKILL.md +37 -0
  164. package/skills/hr-manual-qa/agents/openai.yaml +3 -0
  165. package/skills/hr-navigation-retro/LICENSE +21 -0
  166. package/skills/hr-navigation-retro/NOTICE.md +5 -0
  167. package/skills/hr-navigation-retro/SKILL.md +86 -0
  168. package/skills/hr-navigation-retro/agents/openai.yaml +4 -0
  169. package/skills/hr-navigation-retro/references/inputs.md +67 -0
  170. package/skills/hr-navigation-retro/scripts/retro.py +552 -0
  171. package/skills/hr-navigation-retro/scripts/transcripts.py +205 -0
  172. package/skills/hr-ordering-tests/SKILL.md +51 -0
  173. package/skills/hr-ordering-tests/agents/openai.yaml +2 -0
  174. package/skills/hr-plain-prose/SKILL.md +264 -0
  175. package/skills/hr-plain-prose/agents/openai.yaml +3 -0
  176. package/skills/hr-plain-prose/scripts/check.mjs +331 -0
  177. package/skills/hr-pr-followup/LICENSE +21 -0
  178. package/skills/hr-pr-followup/NOTICE.md +9 -0
  179. package/skills/hr-pr-followup/SKILL.md +74 -0
  180. package/skills/hr-pr-followup/agents/openai.yaml +2 -0
  181. package/skills/hr-pr-followup/references/review-helpers.md +111 -0
  182. package/skills/hr-pr-followup/scripts/check-landing.py +204 -0
  183. package/skills/hr-pr-followup/scripts/check-pr-review.ts +510 -0
  184. package/skills/hr-pr-followup/scripts/merge-pr.sh +100 -0
  185. package/skills/hr-pr-followup/scripts/resolve-pr-thread.ts +219 -0
  186. package/skills/hr-pr-followup/scripts/verify-landed.sh +184 -0
  187. package/skills/hr-progress-report/SKILL.md +49 -0
  188. package/skills/hr-progress-report/agents/openai.yaml +5 -0
  189. package/skills/hr-read-reddit/SKILL.md +44 -0
  190. package/skills/hr-read-reddit/agents/openai.yaml +2 -0
  191. package/skills/hr-read-reddit/scripts/reddit.ts +252 -0
  192. package/skills/hr-read-x-links/SKILL.md +42 -0
  193. package/skills/hr-read-x-links/agents/openai.yaml +2 -0
  194. package/skills/hr-read-x-links/scripts/x-post.ts +264 -0
  195. package/skills/hr-research-shared-links/SKILL.md +103 -0
  196. package/skills/hr-split-to-prs/LICENSE +21 -0
  197. package/skills/hr-split-to-prs/NOTICE.md +9 -0
  198. package/skills/hr-split-to-prs/SKILL.md +61 -0
  199. package/skills/hr-split-to-prs/agents/openai.yaml +2 -0
  200. package/skills/hr-sqlite/SKILL.md +174 -0
  201. package/skills/hr-sqlite/agents/openai.yaml +2 -0
  202. package/skills/hr-sqlite/references/evidence.md +94 -0
  203. package/skills/hr-sqlite/references/tool-decisions.md +39 -0
  204. package/skills/hr-sqlite/scripts/inspect-sqlite.py +245 -0
  205. package/skills/hr-stock-ui-audit/SKILL.md +132 -0
  206. package/skills/hr-stock-ui-audit/agents/openai.yaml +3 -0
  207. package/skills/hr-stock-ui-audit/scripts/scan.mjs +619 -0
  208. package/skills/hr-tdd/LICENSE +21 -0
  209. package/skills/hr-tdd/NOTICE.md +10 -0
  210. package/skills/hr-tdd/SKILL.md +40 -0
  211. package/skills/hr-tdd/agents/openai.yaml +3 -0
  212. package/skills/hr-tdd/mocking.md +39 -0
  213. package/skills/hr-tdd/tests.md +77 -0
  214. package/skills/hr-test-audit/LICENSE +21 -0
  215. package/skills/hr-test-audit/NOTICE.md +67 -0
  216. package/skills/hr-test-audit/SKILL.md +146 -0
  217. package/skills/hr-test-audit/agents/openai.yaml +3 -0
  218. package/skills/hr-test-audit/scripts/floor-guard.ts +137 -0
  219. package/skills/hr-usage-report/SKILL.md +90 -0
  220. package/skills/hr-usage-report/agents/openai.yaml +2 -0
  221. package/skills/hr-usage-report/assets/example-report.json +125 -0
  222. package/skills/hr-usage-report/assets/report-template.html +377 -0
  223. package/skills/hr-usage-report/scripts/render-report.ts +86 -0
  224. package/skills/hr-usage-report/scripts/usage-by-model.ts +499 -0
  225. package/skills/hr-what-next/SKILL.md +151 -0
  226. package/skills/hr-what-next/agents/openai.yaml +4 -0
  227. package/skills/hr-what-next/references/reporting.md +59 -0
  228. package/skills/hr-what-next/scripts/check-open-work.mjs +711 -0
  229. package/skills/hr-writing-for-agents/NOTICE.md +46 -0
  230. package/skills/hr-writing-for-agents/SKILL-MECHANICS.md +83 -0
  231. package/skills/hr-writing-for-agents/SKILL.md +108 -0
  232. package/skills/hr-writing-for-agents/agents/openai.yaml +3 -0
  233. package/skills/hr-writing-pr/NOTICE.md +48 -0
  234. package/skills/hr-writing-pr/SKILL.md +119 -0
  235. package/skills/hr-writing-pr/agents/openai.yaml +2 -0
  236. package/skills/hr-writing-pr/scripts/benefit-chart.py +200 -0
@@ -0,0 +1,269 @@
1
+ # Configure house rules
2
+
3
+ Use `node compose.mjs config help` to see the commands. Bun supports the same
4
+ interface. The CLI manages the existing `house-rules.json`; it keeps personal
5
+ layers, independent skill names and unrelated settings.
6
+
7
+ ## Guided selection
8
+
9
+ Run `node compose.mjs setup --config <config-path>` in a terminal. Bun supports
10
+ the same command. The numbered flow uses ordinary line input; `--plain` selects
11
+ the same flow. Both input and output must be terminals. Redirected input or
12
+ output prints scripting instructions and exits 2 without saving. Use
13
+ `setup --json` for the existing read-only `config status --json` report.
14
+
15
+ Modifiers and skills have stable row numbers while searching. Use `toggle N`
16
+ or `toggle NAME`, with several choices separated by spaces. `search TEXT`,
17
+ `clear search`, `show selected` and `show all` change visibility only.
18
+ `help N` shows the full description, source and invocation policy.
19
+ Excluding a skill name excludes its personal override as well as the shipped
20
+ copy. Exclusions without a current source remain in the configuration.
21
+
22
+ Use `questions default|plain|coded|cards` for question preferences; these modifiers
23
+ are handled together rather than as individual toggles. `next` moves from
24
+ modifiers to skills, then review. `back` keeps the draft. Only `save` on review
25
+ writes configuration. Before a save attempt, `cancel`, end of input or Ctrl-C
26
+ leaves it unchanged.
27
+ A new config with no selection changes is not created.
28
+
29
+ Review includes personal rule origins and an equivalent `config set` command.
30
+ The command uses POSIX quoting on Unix and PowerShell quoting on Windows.
31
+ Personal prose can override the selected preferences; setup does not interpret
32
+ or edit it. Existing composition errors still block saving. Unknown stored
33
+ modifiers can be removed, and a question preset can repair its prerequisite.
34
+ Malformed configuration, legacy skill names and invalid layers require repair
35
+ outside setup.
36
+
37
+ If another writer changes configuration before save, setup preserves the
38
+ draft intent and refuses the stale write. Use `refresh` to compare that intent
39
+ with the fresh configuration, then explicitly save again. It never saves a
40
+ fresh comparison automatically. Saving preserves custom keys and their meaning;
41
+ the writer formats JSON, so existing whitespace is not preserved.
42
+
43
+ If verification fails after saving, configuration may already have changed.
44
+ Inspect `config status` or use `refresh` before another save. Cancelling ends
45
+ the session without undoing an earlier save attempt.
46
+
47
+ Setup saves selections only. Recompose output separately, then connect the
48
+ chosen hosts. It does not install, update, repair or remove managed output.
49
+
50
+ ## Browse and inspect
51
+
52
+ ```bash
53
+ node compose.mjs config catalog --config <config-path>
54
+ node compose.mjs config status --config <config-path>
55
+ node compose.mjs config validate --config <config-path>
56
+ ```
57
+
58
+ `setup` initially shows current selections. Search for relevant additions or
59
+ use `show all` to browse the complete catalog. Review and saving do not require
60
+ a catalog-wide decision.
61
+
62
+ `catalog` shows modifiers, skills and rule sections. `status` shows enabled
63
+ selections and effective personal sources. Both use aligned tables, with color
64
+ in a terminal and stacked rows on narrow screens. `NO_COLOR` disables color.
65
+ Use `--json` for structured output without terminal styling.
66
+
67
+ A missing config is treated as an empty selection without creating files.
68
+ Modifiers are opt-in. Fresh installers copy the sample config with eight skills
69
+ and no modifiers. A missing config or an existing config without `skills.include`
70
+ keeps the full shipped set. The default config path is the same as the composer
71
+ uses. Pass `--config` to choose another.
72
+
73
+ `skills.include` is an optional list of shipped skill names. An empty list selects
74
+ no shipped skills; later shipped additions stay off unless listed. Unknown names,
75
+ malformed lists and duplicates are errors. Personal layer skills still load and
76
+ override shipped skills, even when the shipped name is absent from the list.
77
+ `skills.exclude` takes precedence across every layer. Existing independent names,
78
+ layers and custom settings retain their behavior. The catalog remains complete
79
+ so you can discover additions without enabling them.
80
+
81
+ Status distinguishes configured question preferences from effective rule
82
+ sources. Personal rules can override those preferences. Neither status nor
83
+ validation proves what a running agent has loaded.
84
+
85
+ ## Preview and save
86
+
87
+ ```bash
88
+ node compose.mjs config set --config <config-path> \
89
+ --enable-modifier shared-host-load --disable-skill hr-read-reddit --questions coded
90
+ ```
91
+
92
+ `set` previews by default. It shows the selection changes, composition summary,
93
+ personal rule overrides and current revision. Repeat the exact command with
94
+ `--apply --expect <revision>` to save the reviewed change. Read the new revision
95
+ from the result before another write.
96
+
97
+ Toggle flags can repeat. Enable or disable modifiers with `--enable-modifier`
98
+ and `--disable-modifier`; skills use `--enable-skill` and `--disable-skill`.
99
+ Enabling a skill removes its exclusion. When `skills.include` exists, enabling
100
+ a shipped skill also adds it to that list. Enabling a personal-only skill does
101
+ not add a shipped name. Disabling adds an exclusion, retaining the include list,
102
+ unrelated exclusions and custom settings. Configs without an include list keep
103
+ their existing selection behavior.
104
+
105
+ | Question preset | What you get | Enabled offer modifiers |
106
+ | --------------------- | --------------------------------- | ----------------------------------- |
107
+ | `--questions default` | Model default | `model-default-questions` |
108
+ | `--questions plain` | Text only | Neither offer modifier |
109
+ | `--questions coded` | Text only, with short reply codes | `coded-offers` |
110
+ | `--questions cards` | Clickable choices when available | `coded-offers` and `question-cards` |
111
+
112
+ `default` adds no instruction about how to ask: the model and host ask
113
+ questions their usual way, which on some hosts means clickable choices and on
114
+ others plain text. Core rules, without a preset, keep text only. `default`
115
+ cannot combine with `coded-offers` or `question-cards`.
116
+
117
+ Question presets preserve other modifiers. Choose a preset or explicit offer
118
+ modifier toggles, rather than combining both in one command. Cards still depend
119
+ on the agent host, provider and model. Review any personal Offers override
120
+ before saving; the CLI does not rewrite personal prose.
121
+
122
+ To repair invalid modifier selections, preview changes that produce a valid
123
+ selection. `--questions` can repair the offer dependency; `--disable-modifier`
124
+ can remove an unknown modifier already stored in the config. Malformed config
125
+ structure, unknown enables and unknown disables absent from the config remain
126
+ errors.
127
+
128
+ `preview` accepts the same selection flags without saving. Add `--rules` to
129
+ print the composed rules, or `--json` for the full report. Unknown choices,
130
+ contradictory flags, malformed config and composition errors stop the command
131
+ before it writes configuration. Older skill names need the
132
+ [skill name upgrade](skill-names.md) before composition.
133
+
134
+ ## Optional panel preferences
135
+
136
+ Use `--panel-file <json>` with `config preview` or `config set` to replace only
137
+ the configuration's `panel` section. The input contains the complete preferences
138
+ object, without a surrounding `panel` key. It must be a regular JSON file.
139
+
140
+ ```json
141
+ {
142
+ "version": 1,
143
+ "profile": "balanced",
144
+ "roles": [
145
+ { "id": "correctness", "candidates": ["review-primary", "review-alternative"] },
146
+ { "id": "contrarian", "candidates": ["challenge-primary"] }
147
+ ],
148
+ "policy": {
149
+ "fallback": "approved-only",
150
+ "roundLimit": 1,
151
+ "meteredRoutes": "explicit-approval-required",
152
+ "distinctFamilies": true,
153
+ "excludeAuthorFamily": true,
154
+ "allowReducedPanel": false
155
+ }
156
+ }
157
+ ```
158
+
159
+ ```bash
160
+ node compose.mjs config preview --config <config-path> --panel-file <panel-json>
161
+ node compose.mjs config set --config <config-path> --panel-file <panel-json> \
162
+ --apply --expect <reviewed-config-revision> --expect-panel <reviewed-input-revision>
163
+ ```
164
+
165
+ Preview shows the entire previous and proposed panel section, including ordered
166
+ alternatives. Explicit apply replaces that section; it does not merge role lists.
167
+ Normal selection flags can accompany a panel replacement, with both changes
168
+ covered by the same revision guard. `--rules` cannot accompany `--panel-file`
169
+ because rule output would hide the panel replacement preview.
170
+ Panel input has its own SHA-256 revision. Apply requires `--expect-panel` from
171
+ the preview as well as the config revision, so an edited input file cannot
172
+ silently replace reviewed preferences. A changed input requires another preview.
173
+
174
+ Version 1 requires `version`, a non-empty ordered `roles` array and `policy`.
175
+ Each role has a unique `id` and a non-empty ordered `candidates` array without
176
+ duplicates. Role IDs and candidate aliases start with a lowercase letter, use
177
+ only lowercase letters, digits and hyphens, and contain at most 64 characters.
178
+ Aliases refer to future local bindings; they are not provider/model identifiers.
179
+ The optional `profile` is `quick`, `balanced` or `deep`. It records a preference,
180
+ not a measured performance tier or a seat-count default.
181
+
182
+ Policy requires `fallback` (`none` or `approved-only`), a positive safe-integer
183
+ `roundLimit`, and `meteredRoutes` (`included-only` or
184
+ `explicit-approval-required`). Optional `distinctFamilies`, `excludeAuthorFamily`
185
+ and `allowReducedPanel` are booleans. An omitted policy option is unspecified,
186
+ not permission to bypass a host or project limit. Unknown fields and unsupported
187
+ versions fail an explicit panel operation before configuration writes.
188
+
189
+ The preview reports `proposed`; an explicit save reports `configured`.
190
+ Both report readiness as `unverified`. This feature stores preferences only.
191
+ It does not discover or resolve providers, verify quota or effective effort,
192
+ enforce policy at runtime, enable a skill, change subscriptions or invoke models.
193
+ Exact routes and effort choices belong to local bindings, outside this portable
194
+ schema; the `hr-code-review` skill's `panel-plan.mjs` resolves preferences and
195
+ bindings into seats without calling a model ([contract](../skills/hr-code-review/references/panel-plan.md)). To choose or change seats with the agent, ask it to set up or change your review panel; the skill's [setup procedure](../skills/hr-code-review/references/panel-setup.md) suggests seats from dated recommendations and saves nothing until you confirm. Saving preferences does not authorize spending or waive review gates.
196
+
197
+ Ordinary setup, composition and selection operations preserve existing `panel`
198
+ data without adopting or validating it, including older unrelated uses of that
199
+ key. Before replacing such data, review the full preview. Other selections and
200
+ custom keys are retained. Credentials and provider configuration do not belong
201
+ in the panel input. Input validation checks structure, not secret detection.
202
+
203
+ ## Write safeguards
204
+
205
+ Saving requires the revision reported by status or preview. A stale revision
206
+ fails without overwriting a newer config. Cooperating CLI writers share an
207
+ exclusive `<config-path>.lock` file; a competing writer fails immediately.
208
+ The CLI writes a sibling temporary file, then replaces the config atomically.
209
+ Repeated requests leave an unchanged config's bytes and modification time alone.
210
+ A missing config is created only by explicit apply.
211
+
212
+ Manual editors do not share the lock. Avoid editing the config while a CLI
213
+ write runs. The CLI checks again before replacement, but cannot exclude a
214
+ manual write racing that final replacement. It refuses symlink config files.
215
+ If an interrupted writer leaves a lock, inspect its recorded process ID and
216
+ confirm that writer has ended before removing the lock. The CLI never removes
217
+ another writer's lock automatically.
218
+
219
+ ## Compose and connect
220
+
221
+ Saving changes only configuration. Recompose with the existing composer or run
222
+ the installer again. When the composed skills changed, the installer keeps the
223
+ previous composed skills directory under a dated name; when they match, it keeps
224
+ nothing extra. Manual `--skills-out` still requires an empty or absent directory.
225
+
226
+ ```bash
227
+ node compose.mjs --config <config-path> --out <rules-path> \
228
+ --skills-out <new-skills-directory>
229
+ ```
230
+
231
+ Connecting or copying that output to agent hosts remains a separate setup
232
+ step. Use `hr-house-rules-setup` for the guided workflow. Custom rule prose
233
+ still belongs in layer fragments; the protected completion sections stay
234
+ required.
235
+
236
+ ## Reference output
237
+
238
+ `--out rules.md` writes selected procedure references to a sibling
239
+ `house-rules-references/` directory. Keep that directory beside the rules file
240
+ when copying it to a host. References do not depend on `skills.include` or
241
+ `skills.exclude`. Core Landing and Reporting always contribute their references; enabled modifiers
242
+ contribute theirs. Reporting is also bundled with `hr-what-next` for standalone
243
+ skill use. Excluding that skill does not remove the core reference. A personal replacement suppresses the resource it replaces.
244
+
245
+ The `multi-agent` modifier exports its complete agent-work procedure when enabled,
246
+ including review follow-ups and cleanup qualification. It remains independent
247
+ of selected skills; enabling reference output does not enable the modifier.
248
+
249
+ Use `--references-out <directory>` with `--out` to choose another destination;
250
+ links are rendered relative to the rules file. Keep both locations available.
251
+ Stdout and ordinary composition/configuration API calls retain full inline
252
+ procedures, so existing preview and copy-only workflows need no bundle.
253
+
254
+ A hash manifest permits repeat exports and updates to previously generated
255
+ files. Modified, missing or unrecognized files in that directory stop generation
256
+ before output writes. Reconcile them explicitly; generation never removes old
257
+ procedure files or unrelated files. Output directories must not overlap.
258
+
259
+ Core rule frontmatter may name one `reference` or a comma-separated `references`
260
+ list relative to `rules/core.md`. Use only one form; list paths and section headings
261
+ must be distinct and non-empty. Each target must be a regular file within the
262
+ source layer, with one level-2 heading matching the core section holding its
263
+ mandatory link. Default composition expands that section;
264
+ linked output retains its safety boundaries and reading trigger. Modifier
265
+ references use the same validation and output inventory.
266
+
267
+ For low-level `compose(coreText, fragments)`, use `loadFragments` for personal
268
+ layers so reference paths retain their source ownership. Directly parsed shipped
269
+ modifiers are recognized only when their label and body match the shipped file.
@@ -0,0 +1,50 @@
1
+ # Upgrading skill names
2
+
3
+ Every skill shipped by house-rules uses the `hr-` prefix. For example,
4
+ `handoff` becomes `hr-handoff`. Rule headings, modifier names and the
5
+ `house-rules` command stay the same. Skills from other sources keep their names.
6
+
7
+ ## Before updating
8
+
9
+ 1. In `house-rules.json`, replace each shipped skill name in `skills.exclude`
10
+ with its `hr-` name.
11
+ 2. For each personal override of a shipped skill, rename its directory and
12
+ its frontmatter `name:` to the matching `hr-` name.
13
+ 3. Update your skill invocations, rules, links and host settings to use the
14
+ new names.
15
+
16
+ Composition refuses unresolved old exclusion names, ambiguous old personal
17
+ folders and legacy frontmatter names in prefixed overrides before writing output. The error names the replacement. Fix the
18
+ config or layer, then compose again. The installer keeps the previous composed
19
+ skills until composition succeeds.
20
+
21
+ A personal override named `hr-handoff` replaces the shipped `hr-handoff`.
22
+ If your generic `handoff` is a separate skill you intend to keep alongside it,
23
+ record that decision in your config:
24
+
25
+ ```json
26
+ {
27
+ "skills": {
28
+ "independent": ["handoff"],
29
+ "exclude": ["hr-read-reddit"]
30
+ }
31
+ }
32
+ ```
33
+
34
+ `skills.independent` lets the listed personal skills keep names that match old
35
+ house-rules names. It does not create an alias or replace the prefixed skill.
36
+ `skills.exclude` uses the new names for shipped skills. An old name listed in
37
+ `skills.independent` refers to the independent personal skill and can be excluded
38
+ without excluding its prefixed counterpart. Unrelated personal
39
+ names need no entry in `skills.independent`.
40
+
41
+ ## Connect hosts after composing
42
+
43
+ If a host reads the whole composed directory, point it at the new composed set.
44
+ If it has individual skill links or copied folders, replace its old house-rules
45
+ entries with the matching prefixed entries. Preserve unrelated skills.
46
+ Restart or reload the host and check that it discovers the new names.
47
+
48
+ The composer and installer do not edit host files or remove old host entries.
49
+ Do not keep both the old and new house-rules copies active. Historical skill
50
+ invocations need the new names; there are no compatibility aliases.
@@ -0,0 +1,15 @@
1
+ {
2
+ "modifiers": [],
3
+ "skills": {
4
+ "include": [
5
+ "hr-house-rules-setup",
6
+ "hr-code-review",
7
+ "hr-diagnosing-bugs",
8
+ "hr-explain-code",
9
+ "hr-lean-plan",
10
+ "hr-test-audit",
11
+ "hr-plain-prose",
12
+ "hr-what-next"
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,8 @@
1
+ ---
2
+ after: Implementation economy
3
+ ---
4
+
5
+ ## My tooling
6
+
7
+ Use `pnpm` for JavaScript projects unless the repository already uses another
8
+ package manager. Run the project's own lint and test scripts before committing.
@@ -0,0 +1,9 @@
1
+ ---
2
+ replaces: Reporting
3
+ ---
4
+
5
+ ## Reporting
6
+
7
+ Lead with the result in one sentence, then a short list of what changed, what
8
+ was checked and what is left. Keep reports under 15 lines unless asked for
9
+ detail.
@@ -0,0 +1,18 @@
1
+ # Example project
2
+
3
+ ## Session
4
+
5
+ Before your first reply in a session, read § End of every reply and § Offers in
6
+ your user-level house rules in full. They apply here unchanged; this file only
7
+ adds to them and never removes the offer.
8
+
9
+ ## Landing
10
+
11
+ This repository lands by direct push to `main` after `npm test` passes; that
12
+ is the landing path § Landing asks the repository to name. Never force-push
13
+ `main`.
14
+
15
+ ## Commands
16
+
17
+ - Install: `npm ci`
18
+ - Test: `npm test`
package/package.json CHANGED
@@ -1,6 +1,44 @@
1
1
  {
2
2
  "name": "@bompus/house-rules",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.13.0",
4
+ "description": "Composable working rules and skills for AI coding agents",
5
+ "homepage": "https://github.com/bompus/house-rules#readme",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/bompus/house-rules.git"
10
+ },
11
+ "bin": {
12
+ "house-rules": "compose.mjs"
13
+ },
14
+ "files": [
15
+ "compose.mjs",
16
+ "composition.mjs",
17
+ "rule-references.mjs",
18
+ "config.mjs",
19
+ "config-view.mjs",
20
+ "setup.mjs",
21
+ "rules/",
22
+ "skills/",
23
+ "!skills/*/test/",
24
+ "!**/__pycache__/",
25
+ "docs/",
26
+ "!docs/npm-release.md",
27
+ "examples/",
28
+ "LICENSE",
29
+ "THIRD_PARTY_NOTICES.md",
30
+ "CONTRIBUTING.md",
31
+ "CODE_OF_CONDUCT.md"
32
+ ],
33
+ "type": "module",
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "registry": "https://registry.npmjs.org/"
37
+ },
38
+ "scripts": {
39
+ "check:package": "node scripts/check-package.mjs"
40
+ },
41
+ "engines": {
42
+ "node": ">=22"
43
+ }
44
+ }
@@ -0,0 +1,91 @@
1
+ // Plan reference writes before changing output; retain owned older files, never delete them.
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ existsSync,
5
+ lstatSync,
6
+ mkdirSync,
7
+ readFileSync,
8
+ readdirSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { dirname, join, resolve } from "node:path";
12
+
13
+ const hash = (text) => createHash("sha256").update(text).digest("hex");
14
+ const safeName = (name) => /^[a-z0-9][a-z0-9-]*\.md$/.test(name);
15
+
16
+ export function checkOutputPath(path, directory = false) {
17
+ path = resolve(path);
18
+ for (let current = path; ; current = dirname(current)) {
19
+ let stat;
20
+ try {
21
+ stat = lstatSync(current);
22
+ } catch (error) {
23
+ if (error.code !== "ENOENT") throw error;
24
+ }
25
+ if (stat) {
26
+ if (
27
+ stat.isSymbolicLink() ||
28
+ (current === path && !directory ? !stat.isFile() : !stat.isDirectory())
29
+ )
30
+ throw new Error(`Unsafe output path: ${current}`);
31
+ }
32
+ if (dirname(current) === current) break;
33
+ }
34
+ }
35
+
36
+ export function planReferenceOutput(directory, references) {
37
+ checkOutputPath(directory, true);
38
+ const manifestPath = join(directory, "manifest.json");
39
+ let files = {};
40
+ if (existsSync(directory) && readdirSync(directory).length) {
41
+ if (!existsSync(manifestPath) || !lstatSync(manifestPath).isFile())
42
+ throw new Error(`Unmanaged reference directory: ${directory}`);
43
+ const content = readFileSync(manifestPath, "utf8");
44
+ let manifest;
45
+ try {
46
+ manifest = JSON.parse(content);
47
+ } catch {
48
+ throw new Error(`Invalid reference manifest: ${manifestPath}; reconcile it first`);
49
+ }
50
+ if (
51
+ manifest?.format !== 1 ||
52
+ !manifest.files ||
53
+ typeof manifest.files !== "object" ||
54
+ Array.isArray(manifest.files)
55
+ )
56
+ throw new Error(`Invalid reference manifest: ${manifestPath}`);
57
+ files = manifest.files;
58
+ for (const [name, sha] of Object.entries(files)) {
59
+ if (!safeName(name) || typeof sha !== "string" || !/^[a-f0-9]{64}$/.test(sha))
60
+ throw new Error(`Invalid reference manifest: ${manifestPath}`);
61
+ const path = join(directory, name);
62
+ if (!existsSync(path) || !lstatSync(path).isFile() || hash(readFileSync(path)) !== sha)
63
+ throw new Error(`Modified or missing reference; reconcile it first: ${path}`);
64
+ }
65
+ for (const name of readdirSync(directory)) {
66
+ const path = join(directory, name);
67
+ if (
68
+ lstatSync(path).isSymbolicLink() ||
69
+ (name !== "manifest.json" && !Object.hasOwn(files, name))
70
+ )
71
+ throw new Error(`Unrecognized reference file; reconcile it first: ${path}`);
72
+ }
73
+ }
74
+ const writes = [];
75
+ for (const [name, text] of references) {
76
+ if (!safeName(name) || typeof text !== "string") throw new Error("Invalid reference output");
77
+ if (files[name] !== hash(text)) writes.push({ path: join(directory, name), text });
78
+ files[name] = hash(text);
79
+ }
80
+ const text = JSON.stringify({ format: 1, files }, null, 2) + "\n";
81
+ if (!existsSync(manifestPath) || readFileSync(manifestPath, "utf8") !== text)
82
+ writes.push({ path: manifestPath, text });
83
+ return writes;
84
+ }
85
+
86
+ export function writeReferenceOutput(writes) {
87
+ for (const { path, text } of writes) {
88
+ mkdirSync(dirname(path), { recursive: true });
89
+ writeFileSync(path, text);
90
+ }
91
+ }