principles 0.0.1

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 (278) hide show
  1. checksums.yaml +7 -0
  2. data/exe/principles +10 -0
  3. data/lib/principles/after_commit_hook_options.rb +44 -0
  4. data/lib/principles/cli.rb +149 -0
  5. data/lib/principles/command_line.rb +188 -0
  6. data/lib/principles/command_routes.rb +60 -0
  7. data/lib/principles/controllers/acknowledgement.rb +106 -0
  8. data/lib/principles/controllers/answer.rb +172 -0
  9. data/lib/principles/controllers/audit.rb +203 -0
  10. data/lib/principles/controllers/audit_completion.rb +113 -0
  11. data/lib/principles/controllers/command.rb +201 -0
  12. data/lib/principles/controllers/correction.rb +99 -0
  13. data/lib/principles/controllers/help.rb +107 -0
  14. data/lib/principles/controllers/inventory.rb +181 -0
  15. data/lib/principles/controllers/mapping.rb +56 -0
  16. data/lib/principles/controllers/member_entries.rb +149 -0
  17. data/lib/principles/controllers/members_a_commit_changed.rb +43 -0
  18. data/lib/principles/controllers/members_to_assess.rb +160 -0
  19. data/lib/principles/controllers/meta_principle_setup.rb +92 -0
  20. data/lib/principles/controllers/repoint.rb +68 -0
  21. data/lib/principles/controllers/running_tool.rb +41 -0
  22. data/lib/principles/data/audit_files.rb +96 -0
  23. data/lib/principles/data/bounded_file.rb +45 -0
  24. data/lib/principles/data/candidate_files_found.rb +105 -0
  25. data/lib/principles/data/command-steps.json +305 -0
  26. data/lib/principles/data/command_steps_file.rb +50 -0
  27. data/lib/principles/data/expected_type.rb +71 -0
  28. data/lib/principles/data/ignored_by_git.rb +54 -0
  29. data/lib/principles/data/json_text.rb +57 -0
  30. data/lib/principles/data/known_fields.rb +42 -0
  31. data/lib/principles/data/linked_path.rb +102 -0
  32. data/lib/principles/data/map_files.rb +104 -0
  33. data/lib/principles/data/principle_id.rb +32 -0
  34. data/lib/principles/data/principles_subfolder.rb +93 -0
  35. data/lib/principles/data/project_files.rb +109 -0
  36. data/lib/principles/data/repository.rb +165 -0
  37. data/lib/principles/data/running_version.rb +44 -0
  38. data/lib/principles/data/schema_check.rb +139 -0
  39. data/lib/principles/data/schemas/acknowledgement-answer.schema.json +25 -0
  40. data/lib/principles/data/schemas/answer-guide.schema.json +99 -0
  41. data/lib/principles/data/schemas/assessment-answer.schema.json +332 -0
  42. data/lib/principles/data/schemas/audit-record.schema.json +277 -0
  43. data/lib/principles/data/schemas/command-steps.schema.json +83 -0
  44. data/lib/principles/data/schemas/correction-answer-guide.schema.json +68 -0
  45. data/lib/principles/data/schemas/correction-answer.schema.json +306 -0
  46. data/lib/principles/data/schemas/member-map.schema.json +39 -0
  47. data/lib/principles/data/schemas/repointing-answer.schema.json +44 -0
  48. data/lib/principles/error.rb +102 -0
  49. data/lib/principles/invocation_options.rb +77 -0
  50. data/lib/principles/models/accepted_loading.rb +36 -0
  51. data/lib/principles/models/acknowledgement.rb +203 -0
  52. data/lib/principles/models/activation.rb +64 -0
  53. data/lib/principles/models/agent_loads.rb +64 -0
  54. data/lib/principles/models/answer_fields.rb +67 -0
  55. data/lib/principles/models/answer_place.rb +53 -0
  56. data/lib/principles/models/answer_text.rb +37 -0
  57. data/lib/principles/models/answered_time.rb +65 -0
  58. data/lib/principles/models/assessment_answer.rb +131 -0
  59. data/lib/principles/models/assessment_basis.rb +47 -0
  60. data/lib/principles/models/assessment_report.rb +62 -0
  61. data/lib/principles/models/audit.rb +200 -0
  62. data/lib/principles/models/audit_record.rb +249 -0
  63. data/lib/principles/models/audit_records.rb +103 -0
  64. data/lib/principles/models/audit_start.rb +96 -0
  65. data/lib/principles/models/audited_member_lines.rb +45 -0
  66. data/lib/principles/models/candidate_files.rb +66 -0
  67. data/lib/principles/models/candidate_inventory.rb +67 -0
  68. data/lib/principles/models/candidate_listing.rb +32 -0
  69. data/lib/principles/models/carried_assessments.rb +76 -0
  70. data/lib/principles/models/check_since_last_audit.rb +61 -0
  71. data/lib/principles/models/cited_files.rb +39 -0
  72. data/lib/principles/models/command_steps.rb +270 -0
  73. data/lib/principles/models/commits_brought_in.rb +27 -0
  74. data/lib/principles/models/commits_since_base.rb +32 -0
  75. data/lib/principles/models/correction_answer.rb +66 -0
  76. data/lib/principles/models/correction_basis.rb +70 -0
  77. data/lib/principles/models/dated_line.rb +29 -0
  78. data/lib/principles/models/decided_prior_findings.rb +106 -0
  79. data/lib/principles/models/declared_map_changes.rb +156 -0
  80. data/lib/principles/models/disposition.rb +233 -0
  81. data/lib/principles/models/entry_file.rb +65 -0
  82. data/lib/principles/models/entry_files.rb +46 -0
  83. data/lib/principles/models/evidence_item.rb +48 -0
  84. data/lib/principles/models/evidence_lines_since.rb +57 -0
  85. data/lib/principles/models/evidence_replacements.rb +99 -0
  86. data/lib/principles/models/finding_write_ups.rb +108 -0
  87. data/lib/principles/models/findings_left_open.rb +34 -0
  88. data/lib/principles/models/first_raised_claim.rb +128 -0
  89. data/lib/principles/models/frontmatter_fields.rb +128 -0
  90. data/lib/principles/models/hook_commands.rb +100 -0
  91. data/lib/principles/models/ignored_candidates.rb +46 -0
  92. data/lib/principles/models/json_digest.rb +35 -0
  93. data/lib/principles/models/json_path_query.rb +131 -0
  94. data/lib/principles/models/json_path_selectors.rb +64 -0
  95. data/lib/principles/models/json_path_string.rb +76 -0
  96. data/lib/principles/models/kept_prior_finding.rb +70 -0
  97. data/lib/principles/models/last_completed_revision.rb +70 -0
  98. data/lib/principles/models/line_span.rb +49 -0
  99. data/lib/principles/models/loaded_files.rb +60 -0
  100. data/lib/principles/models/loading_decision.rb +45 -0
  101. data/lib/principles/models/loading_facts.rb +45 -0
  102. data/lib/principles/models/loads_to_check.rb +93 -0
  103. data/lib/principles/models/locate_refusal.rb +23 -0
  104. data/lib/principles/models/located_text.rb +43 -0
  105. data/lib/principles/models/locator.rb +52 -0
  106. data/lib/principles/models/map_members.rb +171 -0
  107. data/lib/principles/models/markdown_file.rb +92 -0
  108. data/lib/principles/models/member.rb +171 -0
  109. data/lib/principles/models/member_assessments.rb +144 -0
  110. data/lib/principles/models/member_elsewhere.rb +74 -0
  111. data/lib/principles/models/member_file.rb +156 -0
  112. data/lib/principles/models/member_grounds.rb +32 -0
  113. data/lib/principles/models/member_history.rb +68 -0
  114. data/lib/principles/models/member_lines.rb +95 -0
  115. data/lib/principles/models/member_loads.rb +197 -0
  116. data/lib/principles/models/member_map.rb +219 -0
  117. data/lib/principles/models/member_map_history.rb +143 -0
  118. data/lib/principles/models/member_maps.rb +185 -0
  119. data/lib/principles/models/member_moves.rb +95 -0
  120. data/lib/principles/models/member_problems.rb +253 -0
  121. data/lib/principles/models/member_sighting.rb +176 -0
  122. data/lib/principles/models/member_snapshots.rb +36 -0
  123. data/lib/principles/models/member_state.rb +35 -0
  124. data/lib/principles/models/members_elsewhere.rb +46 -0
  125. data/lib/principles/models/members_sharing_lines.rb +116 -0
  126. data/lib/principles/models/meta_principle.rb +51 -0
  127. data/lib/principles/models/missing_files.rb +85 -0
  128. data/lib/principles/models/misspelt_member_id.rb +45 -0
  129. data/lib/principles/models/open_finding.rb +221 -0
  130. data/lib/principles/models/open_findings_elsewhere.rb +45 -0
  131. data/lib/principles/models/other_principles.rb +47 -0
  132. data/lib/principles/models/placement.rb +42 -0
  133. data/lib/principles/models/plain_text_file.rb +32 -0
  134. data/lib/principles/models/principles_folder_move.rb +59 -0
  135. data/lib/principles/models/principles_package.rb +53 -0
  136. data/lib/principles/models/prior_finding_decision.rb +162 -0
  137. data/lib/principles/models/prior_finding_outcomes.rb +60 -0
  138. data/lib/principles/models/prior_findings.rb +109 -0
  139. data/lib/principles/models/problem_report.rb +110 -0
  140. data/lib/principles/models/project.rb +214 -0
  141. data/lib/principles/models/project_history.rb +203 -0
  142. data/lib/principles/models/record_judged_against.rb +42 -0
  143. data/lib/principles/models/recorded_entry.rb +93 -0
  144. data/lib/principles/models/recorded_finding.rb +97 -0
  145. data/lib/principles/models/recorded_findings.rb +58 -0
  146. data/lib/principles/models/recorded_members.rb +149 -0
  147. data/lib/principles/models/repoint.rb +112 -0
  148. data/lib/principles/models/reported_check.rb +130 -0
  149. data/lib/principles/models/request_id.rb +70 -0
  150. data/lib/principles/models/runs_from.rb +36 -0
  151. data/lib/principles/models/skill_loads.rb +123 -0
  152. data/lib/principles/models/still_holds_restatement.rb +87 -0
  153. data/lib/principles/models/text_size.rb +26 -0
  154. data/lib/principles/models/uncommitted_outside_the_map.rb +30 -0
  155. data/lib/principles/models/waits_on.rb +58 -0
  156. data/lib/principles/models/write_up_opening.rb +93 -0
  157. data/lib/principles/models/write_up_pointer.rb +50 -0
  158. data/lib/principles/models/write_up_repoint.rb +39 -0
  159. data/lib/principles/prose_list.rb +23 -0
  160. data/lib/principles/supported_ruby.rb +93 -0
  161. data/lib/principles/version.rb +11 -0
  162. data/lib/principles/views/acknowledged_since_last_audit.rb +34 -0
  163. data/lib/principles/views/acknowledgement_result.rb +44 -0
  164. data/lib/principles/views/activation_in_hand.rb +47 -0
  165. data/lib/principles/views/assessment_request.rb +131 -0
  166. data/lib/principles/views/audit_changes.rb +79 -0
  167. data/lib/principles/views/audit_commit.rb +55 -0
  168. data/lib/principles/views/audit_result.rb +147 -0
  169. data/lib/principles/views/candidate_files_result.rb +95 -0
  170. data/lib/principles/views/check_result_template.rb +75 -0
  171. data/lib/principles/views/diff_since_last_audit.rb +29 -0
  172. data/lib/principles/views/findings_result.rb +45 -0
  173. data/lib/principles/views/help.rb +119 -0
  174. data/lib/principles/views/invocation.rb +66 -0
  175. data/lib/principles/views/landed_since_base.rb +27 -0
  176. data/lib/principles/views/lines_shared_with_member.rb +111 -0
  177. data/lib/principles/views/loads_to_check_result.rb +45 -0
  178. data/lib/principles/views/map_result.rb +169 -0
  179. data/lib/principles/views/member_change_since_baseline.rb +58 -0
  180. data/lib/principles/views/member_repairs.rb +82 -0
  181. data/lib/principles/views/members_a_commit_changed.rb +66 -0
  182. data/lib/principles/views/members_with_no_baseline.rb +56 -0
  183. data/lib/principles/views/meta_principle_passage.rb +23 -0
  184. data/lib/principles/views/meta_principle_result.rb +170 -0
  185. data/lib/principles/views/open_findings_elsewhere_result.rb +32 -0
  186. data/lib/principles/views/open_findings_line.rb +125 -0
  187. data/lib/principles/views/other_principles_unjudged_result.rb +32 -0
  188. data/lib/principles/views/outside_the_map_result.rb +31 -0
  189. data/lib/principles/views/package_since_last_audit_result.rb +34 -0
  190. data/lib/principles/views/principle_read_result.rb +86 -0
  191. data/lib/principles/views/principle_with_changed_members.rb +26 -0
  192. data/lib/principles/views/principles_with_no_completed_audit.rb +30 -0
  193. data/lib/principles/views/printed_principle.rb +45 -0
  194. data/lib/principles/views/prior_finding_decisions_result.rb +35 -0
  195. data/lib/principles/views/prior_findings_result.rb +80 -0
  196. data/lib/principles/views/problem_lines.rb +84 -0
  197. data/lib/principles/views/problem_result.rb +107 -0
  198. data/lib/principles/views/prompts/acknowledge-a-change/say-whether-the-change-keeps-the-meaning.md +12 -0
  199. data/lib/principles/views/prompts/answer-any-judgement-request/what-a-self-audit-cannot-show.md +6 -0
  200. data/lib/principles/views/prompts/assess-every-member/answer-guide.json +63 -0
  201. data/lib/principles/views/prompts/assess-every-member/assess-each-member-and-the-set.md +12 -0
  202. data/lib/principles/views/prompts/assess-every-member/check-roles-other-principles-give-these-lines.md +7 -0
  203. data/lib/principles/views/prompts/assess-every-member/decide-each-member-loading.md +17 -0
  204. data/lib/principles/views/prompts/assess-every-member/decide-each-prior-finding.md +38 -0
  205. data/lib/principles/views/prompts/assess-every-member/give-problem-evidence-at-still-holds.md +2 -0
  206. data/lib/principles/views/prompts/assess-every-member/give-the-evidence-a-prior-finding-lacks.md +7 -0
  207. data/lib/principles/views/prompts/assess-every-member/have-a-changed-check-reviewed-before-running-it.md +4 -0
  208. data/lib/principles/views/prompts/assess-every-member/have-a-new-check-reviewed-before-running-it.md +3 -0
  209. data/lib/principles/views/prompts/assess-every-member/have-hidden-characters-in-a-check-explained.md +4 -0
  210. data/lib/principles/views/prompts/assess-every-member/judge-acknowledged-edits-together.md +6 -0
  211. data/lib/principles/views/prompts/assess-every-member/judge-the-keeping-against-the-other-principles.md +7 -0
  212. data/lib/principles/views/prompts/assess-every-member/judge-the-keeping-under-the-release-since-the-last-audit.md +10 -0
  213. data/lib/principles/views/prompts/assess-every-member/judge-the-set-with-carried-assessments.md +10 -0
  214. data/lib/principles/views/prompts/assess-every-member/keep-the-last-review-basis-unless-you-give-a-new-one.md +1 -0
  215. data/lib/principles/views/prompts/assess-every-member/name-another-principles-open-finding-rather-than-raise-it.md +9 -0
  216. data/lib/principles/views/prompts/assess-every-member/read-whether-each-prior-finding-s-evidence-changed.md +12 -0
  217. data/lib/principles/views/prompts/assess-every-member/run-a-named-check-at-every-full-audit.md +2 -0
  218. data/lib/principles/views/prompts/assess-every-member/run-the-check-then-report-it.md +2 -0
  219. data/lib/principles/views/prompts/assess-every-member/run-the-reviewed-check-and-say-what-its-review-rested-on.md +6 -0
  220. data/lib/principles/views/prompts/assess-every-member/uncommitted-files-outside-the-map.md +4 -0
  221. data/lib/principles/views/prompts/assess-every-member/why-each-member-is-judged-again.md +24 -0
  222. data/lib/principles/views/prompts/dispose-of-each-finding/answer-guide.json +34 -0
  223. data/lib/principles/views/prompts/dispose-of-each-finding/fix-or-record-each-finding.md +24 -0
  224. data/lib/principles/views/prompts/find-a-principle-to-map/ask-the-owner-before-mapping.md +1 -0
  225. data/lib/principles/views/prompts/find-a-principle-to-map/choose-one-principle.md +5 -0
  226. data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-ignored-folders.md +2 -0
  227. data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-ignored.md +3 -0
  228. data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-possibly-test-data.md +2 -0
  229. data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-untracked.md +2 -0
  230. data/lib/principles/views/prompts/find-a-principle-to-map/what-each-command-writes.md +4 -0
  231. data/lib/principles/views/prompts/find-a-principle-to-map/where-the-inventory-looks.md +10 -0
  232. data/lib/principles/views/prompts/learn-what-a-command-does/add-member.md +45 -0
  233. data/lib/principles/views/prompts/learn-what-a-command-does/change-activation.md +21 -0
  234. data/lib/principles/views/prompts/learn-what-a-command-does/change-description.md +2 -0
  235. data/lib/principles/views/prompts/learn-what-a-command-does/change-member-check.md +17 -0
  236. data/lib/principles/views/prompts/learn-what-a-command-does/change-member-role.md +9 -0
  237. data/lib/principles/views/prompts/learn-what-a-command-does/create-principle.md +6 -0
  238. data/lib/principles/views/prompts/learn-what-a-command-does/every-command-and-how-they-chain.md +28 -0
  239. data/lib/principles/views/prompts/learn-what-a-command-does/list-candidate-files.md +17 -0
  240. data/lib/principles/views/prompts/learn-what-a-command-does/list-member-problems.md +73 -0
  241. data/lib/principles/views/prompts/learn-what-a-command-does/list-open-findings.md +71 -0
  242. data/lib/principles/views/prompts/learn-what-a-command-does/list-principles.md +7 -0
  243. data/lib/principles/views/prompts/learn-what-a-command-does/move-member.md +11 -0
  244. data/lib/principles/views/prompts/learn-what-a-command-does/remove-member-check.md +10 -0
  245. data/lib/principles/views/prompts/learn-what-a-command-does/remove-member.md +6 -0
  246. data/lib/principles/views/prompts/learn-what-a-command-does/show-answer-check.md +16 -0
  247. data/lib/principles/views/prompts/learn-what-a-command-does/show-audit.md +20 -0
  248. data/lib/principles/views/prompts/learn-what-a-command-does/show-meta-principle-passage.md +52 -0
  249. data/lib/principles/views/prompts/learn-what-a-command-does/show-principle.md +86 -0
  250. data/lib/principles/views/prompts/learn-what-a-command-does/start-audit.md +68 -0
  251. data/lib/principles/views/prompts/learn-what-a-command-does/submit-answer.md +56 -0
  252. data/lib/principles/views/prompts/repoint-write-ups/point-each-moved-write-up-at-its-new-place.md +10 -0
  253. data/lib/principles/views/prompts/report-after-a-commit/it-refused-after-the-commits-touched-the-maps.md +2 -0
  254. data/lib/principles/views/prompts/report-after-a-commit/others-are-still-listed.md +1 -0
  255. data/lib/principles/views/prompts/report-after-a-commit/the-commits-changed-these-members.md +2 -0
  256. data/lib/principles/views/prompts/report-after-a-commit/this-command-shows-each-one.md +1 -0
  257. data/lib/principles/views/prompts/report-the-completed-audit/commit-only-what-the-audit-changed.md +2 -0
  258. data/lib/principles/views/prompts/report-the-completed-audit/replace-the-default-commit-message.md +4 -0
  259. data/lib/principles/views/prompts/report-the-completed-audit/what-completion-means.md +2 -0
  260. data/lib/principles/views/prompts/set-principles-up/entry-file-passage.md +3 -0
  261. data/lib/principles/views/prompts/set-principles-up/name-the-step-each-member-lacks.md +15 -0
  262. data/lib/principles/views/prompts/set-principles-up/place-the-passage-with-the-user.md +31 -0
  263. data/lib/principles/views/prompts/set-principles-up/set-up-first.md +2 -0
  264. data/lib/principles/views/prompts/set-principles-up/what-the-passage-presumes.md +4 -0
  265. data/lib/principles/views/prompts/start-a-session/act-on-the-open-findings.md +5 -0
  266. data/lib/principles/views/prompts/start-a-session/it-returns-after-each-clear-or-compaction-too.md +1 -0
  267. data/lib/principles/views/prompts/start-a-session/it-returns-at-each-session-start.md +1 -0
  268. data/lib/principles/views/prompts/start-a-session/raise-them-at-the-next-pause.md +1 -0
  269. data/lib/principles/views/prompts/start-a-session/raise-them-before-the-first-task.md +1 -0
  270. data/lib/principles/views/prompts.rb +71 -0
  271. data/lib/principles/views/repoint_result.rb +80 -0
  272. data/lib/principles/views/request_part.rb +26 -0
  273. data/lib/principles/views/request_parts.rb +26 -0
  274. data/lib/principles/views/shell_word.rb +29 -0
  275. data/lib/principles/views/visible_text.rb +26 -0
  276. data/lib/principles/views/workflow_diagram.rb +77 -0
  277. data/lib/principles.rb +5 -0
  278. metadata +326 -0
@@ -0,0 +1,86 @@
1
+ Shows each member of principle ID, where its text is now and whether it changed since the last audit. Audit when a
2
+ member is changed, unassessed, locator_lost or unavailable. A member that is locator_lost or unavailable carries
3
+ `repair_with`: a `move-member` with its `NEW_PATH`, `HEADING` or `QUERY` to fill in, for a section or passage a
4
+ second `move-member` for text moved into another file, and a `remove-member`. Run the one that fits;
5
+ `next_action` names those members.
6
+
7
+ Each member's `loads` says, for each host this tool derives, when that host loads the member's file into the agent's
8
+ context. Only `claude_code` is derived; Codex is not yet. The derivation follows Claude Code's documented loading
9
+ from the file's path alone, for a session started at the project root, not what loaded in any session:
10
+
11
+ - `session_start`: the project's `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md`, in every session.
12
+ - `on_files` with `files`: one of those files in a folder below the root, once a file in that folder is read,
13
+ written or edited.
14
+ - `session_start` too: a rule in `.claude/rules/`, or a folder within it, without a `paths` field in its
15
+ frontmatter.
16
+ - `on_files` with `paths_field`: a rule with a `paths` field, once a file it matches is read, written or edited.
17
+ `paths_field` is the field's lines as written; this tool does not read the globs, so read them yourself.
18
+ - `on_invocation`: a skill's `SKILL.md` in `.claude/skills/NAME/`, whose body loads when the skill is invoked.
19
+ `invoked_by` is `model_or_person`, or `person` when its frontmatter says `disable-model-invocation: true`, so only
20
+ a person's `/NAME` invokes it. This tool reads that field only as a plain `true` or `false` on its line.
21
+ `description` says when the skill's description, which tells the model the skill exists, loads: `session_start`;
22
+ `on_files` with `paths_field`, for a skill with a `paths` field; `on_files` with `files`, for a skill in a folder
23
+ below the root; or `not_loaded`, for a skill only a person invokes. Other files in a skill's folder are
24
+ `no_known_carrier`: the skill's body may tell the agent to read them. A member that is the skill's description
25
+ field, by a query that names its `description` field such as `$.description`, has `skill_part: description` and
26
+ the description's moment as its own `when`, with only its own `member_bytes`, since the file's size is the body's
27
+ cost; any other frontmatter field's member gets the body's answer.
28
+ - `on_delegation` with `context: subagent`: a subagent's definition, a `.md` file at any depth in `.claude/agents/`.
29
+ Its body is the subagent's own system prompt, loaded in the subagent's context, not the main session's, when
30
+ Claude delegates to it; `description` is `session_start`, since Claude reads every subagent's description to
31
+ decide when to delegate. An agents folder below the root, or an agent file without a `description` field, such as
32
+ a note kept beside the agents, is `not_determined`.
33
+ - `not_determined`: This tool knows the file is a rule, a skill or an agent but not when it loads.
34
+ `frontmatter_refused` names the code this tool refused its frontmatter with, so read the frontmatter; `not_derived`
35
+ names a kind it does not derive yet, such as a rules folder below the project root.
36
+ - `no_known_carrier`: This tool knows no Claude Code facility that loads this path by itself. An `@` import from
37
+ another instruction file, or a user-level file, may still load it; read the importing file to check.
38
+
39
+ Whatever `when` says, `named_in_hooks` lists each project hook whose command names the member's file: its `settings`
40
+ file, `event`, `matcher` (left out when the event has none), and `command` and `args` as written. A command names
41
+ the file when it or one of its args gives the file's path from the project root, bare or after
42
+ `$CLAUDE_PROJECT_DIR`; a path reached another way, such as after a `cd`, is not recognised. This tool does not run
43
+ the command, so a name is not proof the hook runs the file, and it says nothing of whether the hook's output reaches
44
+ context: that depends on the event and on what the command prints, so read the event in Claude Code's hooks
45
+ documentation and the script. It reads only command handlers in `.claude/settings.json` and
46
+ `.claude/settings.local.json`; the local file is this checkout's own, and a handler in both runs once. It reads the
47
+ local file even where git ignores it, as Claude Code runs its hooks either way, so an owner's personal commands can
48
+ show here; list-candidate-files leaves an ignored file out of what it lists to map, not out of what loads. This tool
49
+ only prints them here and never writes them to a map or an audit record; if you quote one in an audit answer, that
50
+ answer is written to the audit record, which the project commits, so leave a personal command out of it. It does not
51
+ read user, managed, plugin or skill and agent frontmatter hooks, `prompt` or `agent` handlers, or `disableAllHooks`.
52
+ `hook_settings_not_read` names each of those two settings files this tool could not read, with its refusal code, so
53
+ an unreadable file is not taken for one without hooks.
54
+
55
+ A carrier loads its whole file, so `file_bytes` is the file's size, shared by every member in it, and
56
+ `estimated_tokens` is its characters divided by four, rounded up: an estimate, not a tokenizer count. For a skill,
57
+ they are what its body costs once invoked, and for an agent what its body costs in the subagent's context; the
58
+ description is a smaller part of the file. A `loads` without `context` loads into the main session's context.
59
+ `member_bytes` and `member_tokens` are the member's own lines, its share of that file, which moving the member out
60
+ of it would save; for a member that is its whole file they equal `file_bytes` and `estimated_tokens`, and they are
61
+ left out when this tool cannot find the member in its file.
62
+ Those lines may be other members' too: `overlaps` names this principle's members sharing a line with it, `same_lines_as`
63
+ those spanning exactly its lines, and `mapped_elsewhere` other principles' members, each with its role, `first_line`,
64
+ `last_line`, and `same_lines` when spanning exactly the same lines, `spans_these_lines` when its lines include all of
65
+ this member's, or `within_these_lines` when they all lie within this member's. Each is left out when none shares a line.
66
+ Before narrowing a section to save its `member_bytes`, check whose lines they are.
67
+
68
+ Members in one file each show that file's size, so adding up the members counts a shared file once per member.
69
+ `files_loaded` lists each file the members load once, with its `path`, when it loads and its size, as a member's
70
+ `loads.claude_code` gives them, leaving out a file with no known carrier; the hooks that name a file show on its
71
+ members. `session_start_total` adds up the files that load whole at session start, the one moment
72
+ they all load together; the files that load on files, on invocation or on delegation each load apart, so they are not
73
+ added up. Beside them, `descriptions` gives the `count` of skill and agent descriptions that load at session start
74
+ while their bodies wait, with their `description_bytes` and `description_tokens`: for a skill, its `description` and
75
+ `when_to_use` lines together, cut at 1,536 characters as Claude Code cuts each skill's listing
76
+ (code.claude.com/docs/en/skills, read 2026-11-09; a `skillListingMaxDescChars` setting changes that cap), and for an
77
+ agent its `description` lines. A skill only a person can invoke is left out, since its description does not load.
78
+ They are measured as written, each line with its key, quoting and trailing newline, so they are an estimate of what
79
+ the listing holds, and a skill's can exceed a description member's own `member_bytes` when it has `when_to_use`.
80
+ The total leaves out a file this tool cannot read, and whatever this principle does not map, such as user-level files,
81
+ imports and hook output: it is what this principle's own files cost at start, not what a session starts with. The
82
+ files and descriptions it counts load at start whatever its activation, since the host loads them before an agent
83
+ reads the principle; the activation says when the agent works with the principle, and its other members load as their
84
+ own `when` says. Both are left out when there is nothing to list. Within the total, `files`, `file_bytes` and
85
+ `estimated_tokens` are left out when no file that loads whole at start could be measured, as `descriptions` is when
86
+ no description could; a file listed in `files_loaded` with no size loads at start uncounted.
@@ -0,0 +1,68 @@
1
+ Asks you to assess every member of principle ID and the set as a whole. Run it after mapping, and again when
2
+ `show-principle` reports a member changed, unassessed, locator_lost or unavailable.
3
+
4
+ `start-audit` itself writes nothing. `submit-answer` writes the audit record, `.principles/audits/ID.json`: a full audit
5
+ writes it completed when its assessment has no findings or its correction is accepted. In git, commit the record each
6
+ time it is written, as `files_to_commit` lists it. In a full audit, make each fix after the assessment is accepted and
7
+ before you submit the correction that reports it, or the assessment is refused as `stale_request`, as is an edited
8
+ `basis`, whose `basis.last_completed_revision` names the record it follows, or null for none. The audit judges the text
9
+ now: a problem no completed audit recorded and fixed before `start-audit` is not recorded, and a deferred or accepted
10
+ finding fixed since is decided `resolved`. To record one, commit a revert, run the audit, and redo it in the correction.
11
+
12
+ It refuses with `broken_members` while any member cannot be found or read; `missing_files` groups them by file. A member
13
+ with a check carries `check_since_last_audit`, and `check_hidden_characters` when its check hides characters.
14
+ `mapped_elsewhere` shows other principles' members on its lines, judged as `mapped_elsewhere_instruction` says, with
15
+ `open_finding_ids` from `open_findings_elsewhere`, whose `evidence` items say `shares_lines_with`, `shares_no_lines`,
16
+ `whole_file` or `not_located`, or which says `evidence_not_kept`. In git, `context.uncommitted_files_outside_the_map`
17
+ lists up to ten files outside the map that differ from the base commit or are untracked, `not_named` counting the rest.
18
+ A meta-principle audit adds `package_since_last_audit`, `passage_changed` and `other_principles_with_unjudged_changes`.
19
+
20
+ ## Since the last full audit
21
+
22
+ After a full audit, each member carries `carried_forward`, with its `assessed_at`, an observed one's `observed_at` (or
23
+ `observed_at_from_assessed_at`), `evidence_changed` and, in git, `file_changed_outside_member`, or else `judge_because`
24
+ with `read_the_change`, and a moved one `moved_from`; `carried_forward_instruction` and `judge_because_instruction`
25
+ explain them. One acknowledged with `--member` since carries `acknowledged_since_last_audit`, with that audit's
26
+ `last_audited_commit`, each acknowledgement and its lines then and now, or `{"omitted": "not_found_at_last_audit"}` when
27
+ it has moved. A new or changed check's exit status needs `review_basis`: what its review rested on, kept unverified. An
28
+ unchanged check also shows its `review_basis` and `review_basis_since`, a changed one `last_run_review_basis`.
29
+
30
+ ## Prior findings
31
+
32
+ When the last completed audit deferred or accepted findings, `context.prior_findings` lists them, with `first_raised_at`
33
+ and a deferral's `waits_on` and `waits_on_since`. Decide each in `prior_finding_decisions` as `still_holds`, `resolved`,
34
+ `withdrawn` or `raised_again`, as `context.prior_findings_instruction` says. An older finding may claim an earlier
35
+ `first_raised_at` with `raised_in`, from `git log --follow -p -- .principles/audits/ID.json`. Each gives its `evidence`,
36
+ in git each item with `changed_since_last_audit` and `found_now`, or `evidence_not_kept` and an `evidence_request` for
37
+ `problem_evidence`, whose `replaces` re-points a lost item. The result names drops and re-points:
38
+ `prior_findings_pointers_dropped`, `prior_findings_waits_on_dropped`, `prior_findings_evidence_replaced`.
39
+
40
+ ## Members to check against the activation
41
+
42
+ When the principle's activation is a set of files, `context.loads_to_check_against_activation` lists each member whose
43
+ file Claude Code loads at session start, with its `loads` and `listed_for`, to weigh whether a principle meant for that
44
+ work loads in every session; this tool compares no globs, and `not_listed_no_known_carrier` names the members this tool
45
+ knows no carrier for. Decide every row in `loading_decisions`, as `context.loads_to_check_instruction` explains, or this
46
+ tool refuses it with `incomplete_loading_decisions`. The record keeps an accepted decision as `loading_accepted`, which
47
+ the next audit shows as `last_accepted`, with `last_accepted.since_accepted` and whether `member_text` or `loading`
48
+ changed. Not listed yet: members loading on files, skills or agents, members this tool could not determine, members a
49
+ hook names, and anything under an invoked or always activation or in a one-member audit.
50
+
51
+ ## One member's edit: `--member`
52
+
53
+ Use `--member MEMBER` when one member was edited but still says the same thing, as `list-member-problems --help`
54
+ describes; without it, `list-member-problems --short` reports the edit at every commit until a full audit. Its request
55
+ shows the `baseline_commit` it was last judged at, `member_lines` then and now (or a long member's `changed_region`,
56
+ `context_lines` and `from_line`, or `read_instead`), `read_the_change` and the member's `deferred_findings` and
57
+ `accepted_findings`, which stay; its `question` asks for `meaning_kept`. This tool checks both quotes. An id near a
58
+ mapped one is refused with `unknown_member`, naming the mapped one under `did_you_mean`. A one-member audit writes the
59
+ record once its answer is accepted, keeping the edit in the member's `acknowledgements`; commit it. It is refused with
60
+ `cannot_acknowledge` outside git, while an audit is open, and for a member no completed audit assessed or whose text at
61
+ its baseline commit does not match the audit record; until built, it is refused for a member with a check: run a full
62
+ audit. A member moved with `move-member` since its baseline carries `evidence_at_baseline`, and one the last full
63
+ audit's correction fixed carries `audit_base_commit`: judge only the change since `baseline_commit`.
64
+
65
+ ## Outside git
66
+
67
+ In a project outside git, an assessment with findings writes an open record, which the accepted correction completes.
68
+ Until then it keeps the prior findings to list again; one opened by an older version of this tool kept none.
@@ -0,0 +1,56 @@
1
+ Gives your answer to request REQUEST, built from that request's `response_template`. Write the JSON to a FILE outside
2
+ the project and pass `--file FILE`, which needs no shell quoting; `--file -` reads stdin. This tool edits none of the
3
+ project's files. In a full audit, make each fix after the assessment is accepted and before you submit the correction
4
+ that reports it: an earlier fix changes a member the request was computed from, and is refused as `stale_request`.
5
+ Answer each request once. If another full audit of the principle completed, or a member was acknowledged, after an
6
+ assessment or correction request was printed, its answer is refused as `audit_completed_since_request`, since it would
7
+ replace the newer record and drop what it left open: run `list-open-findings ID`, then start the audit again. Copy the
8
+ basis unchanged: its `last_completed_revision` says which record its request was printed after. The same answer
9
+ submitted again after it completed the audit writes nothing, and is accepted; an assessment whose correction completed
10
+ the audit is refused instead, since it would print a new correction.
11
+ An observed assessment may give `observed_at`, when you saw what `observation` describes, as a UTC time like
12
+ `2026-11-01T09:30:00Z`; none or null dates it at this audit's time. When the sighting is a dated record you read during
13
+ this audit, `observed_at` is the record's date, not when you read it. Another form, a time after the answer, or any on a
14
+ not_observed one, even null, is refused as `invalid_answer`. An `observation` judged afresh copying the last full
15
+ audit's word for word is refused as `observation_repeats_last_audit` unless `observed_at` is the date it names or null:
16
+ the date if you kept that sighting; reword a later one, null if in this audit. It checks no reworded text.
17
+ When this tool cannot place a piece of evidence or a `recorded_at`, such as a quote that occurs twice
18
+ (`ambiguous_passage`), or refuses a `check_result` (`invalid_check_result`), the refusal keeps its code, any `path`
19
+ and repair, starts its message with whose it is, such as "Finding F1" or "Member CLAUDE.md#Names", and gives `fields`,
20
+ each with its `problem` and the JSON `pointer` into your answer.
21
+ The correction template leaves each `action` null for you to choose: fixed, deferred, accepted or disagreed; a null or
22
+ unknown one is refused as `invalid_disposition`, naming the finding. A deferred disposition may give `waits_on`, one
23
+ line saying whom the finding waits on and to decide what, such as "<person>, to approve a CI change", which
24
+ `list-open-findings` prints. Null, accepted on any disposition, says it waits on no one; a line on any other action, or
25
+ one that spans lines, is refused as `invalid_disposition`. This tool records when it was asked; never send that time.
26
+ A full audit's `still_holds` decision on a prior finding may give `first_raised_at` with `raised_in`, the full sha of a
27
+ commit whose audit record, at `.principles/audits/ID.json` or the earlier `.memeplex/audits/ID.json`, left the same
28
+ finding open then, deferred or accepted, with `first_raised_at` that record's `audited_at`, to date a finding from
29
+ records older than the field. Give both or neither; this tool reads only that commit, and whether it is the same finding
30
+ is yours to judge. A claim it cannot confirm is refused, saying why and how to repair it: `raised_in_not_found`, as
31
+ outside git, `raised_in_unreadable`, `raised_in_lacks_finding`, `raised_in_time_differs`, or `first_raised_not_earlier`
32
+ when it is not earlier than the time stored.
33
+ A completed full audit's `open_findings` are the ids `list-open-findings` will list, its own and kept prior ones,
34
+ deferred or accepted; `resolved_findings`, those fixed now and prior ones decided resolved. A disagreed or withdrawn
35
+ finding is in neither; `prior_findings_closed` gives each prior one closed, with its decision and reason.
36
+ In git, `commits_since_base` lists by member id the commits since the base touching its file; an uncommitted fix shows
37
+ an empty list, `files_to_commit` names its file, and `commit_with`, its `-m` default replaced as
38
+ `commit_message_to_replace` says, commits only those, stopping during an unfinished merge. In or out of git,
39
+ `cited_files_missing` names each file the record cites that no longer exists, which `files_to_commit` leaves out though
40
+ the record still points at it. If HEAD moved but no commit touched one, `head_moved_past_base` gives `base_commit` and
41
+ `head`. If its fixes changed a file another principle also maps, `other_principles_with_changed_members` names each such
42
+ principle and its members in fixed findings' files, by `id` with the `state` `list-member-problems` gives: `changed`
43
+ when its text now differs from its baseline, or `locator_lost` or `unavailable` when the fix broke where this tool finds
44
+ it, which its `repair_with` on `show-principle ID` repairs. Then re-audit that principle, or acknowledge a member's edit
45
+ with `start-audit ID --member MEMBER`. A changed file no fixed finding names is not checked.
46
+
47
+ A fix changing a member's role or check with `change-member-role` or `change-member-check` lists its id, after any move,
48
+ in `changed_map_entries`, which only a fixed disposition may list, and may leave `changed_members` empty. A fix mapping
49
+ a missing member with `add-member` names it in `changed_members`. In git, this tool reads the map the audit began from
50
+ and refuses with `stale_map` when anything else changed, a removal too, after any `moved_members`, and
51
+ `claimed_change_missing` when a listed role and check are as they were; `files_to_commit` names the map. An added member
52
+ gets no baseline: `members_added_awaiting_assessment` names it for the next full audit. Outside git, defer the finding:
53
+ an entry is refused as `map_entries_need_git`, an added member as `stale_map`.
54
+
55
+ For a `start-audit --member` request, this tool checks `old_line` at the baseline commit and `new_line` now, refuses
56
+ with `quote_not_found` when either is not found, and prints `acknowledged` with the record in `files_to_commit`.
@@ -0,0 +1,10 @@
1
+ Each open finding in `findings` has its `recorded_at`, and what list-open-findings says of the write-up there: its
2
+ `write_up_opening`, or why there is none in `write_up_opening_reason`. When the file is missing, git's match for it is
3
+ in `write_up_opening_error.git_detected_rename`, with `starting_at_found_in_rename` when the pointer quotes a
4
+ `starting_at`. Git's match can pair a deleted file with an unrelated similar one, so read the file it names before you
5
+ use it. For each finding whose write-up you found, set its `recorded_at` in `repoints` to where the write-up is now,
6
+ as `{"path": ..., "heading": ...}` or with `starting_at`, and give a one-line `reason`. Leave `recorded_at` null for a
7
+ finding you do not repoint. Only `recorded_at` changes: the finding stays open, with its problem, action and dates,
8
+ for the next full audit to decide. During a full audit, give the new `recorded_at` in that finding's still_holds
9
+ decision instead, since a repoint changes the record that audit's request was printed after. Do not edit the audit
10
+ record by hand: nothing would check that the new pointer is found.
@@ -0,0 +1,2 @@
1
+ principles: list-member-problems refused with %{code} after commits that changed this project's maps or
2
+ mapped files. This command shows why and how to repair it:
@@ -0,0 +1 @@
1
+ %{count} other changed %{members} still listed from earlier commits.
@@ -0,0 +1,2 @@
1
+ principles: the commits this Bash call brought in changed these mapped members, one per line with its
2
+ principle, id, newest changing commit, that commit's subject and what it was compared with:
@@ -0,0 +1 @@
1
+ This command shows each one and what to do next:
@@ -0,0 +1,2 @@
1
+ Commit %{files}, and nothing else staged, with the command that ends this line, after replacing its default `-m`
2
+ message as `commit_message_to_replace` says. Commit with: %{command}
@@ -0,0 +1,4 @@
1
+ The `-m` message in `commit_with`, "%{subject}", is a default: replace it with a subject in your project's own
2
+ convention, such as a ticket prefix, before running it, since a commit hook may refuse the default. For a message with
3
+ a body or trailer, write it to a file and put `-F <file>` in place of `-m` and its subject; a file needs no shell
4
+ quoting, and a relative path to it resolves from the project, which the command changes into first.
@@ -0,0 +1,2 @@
1
+ Completion records assessment coverage, not certification. Fixed is the agent's judgement plus a
2
+ checked change; delivery is credited only as the agent reported it.
@@ -0,0 +1,3 @@
1
+ ## %{heading}
2
+
3
+ Where `principles` is installed, run `principles list-member-problems --short` at each session start, after a compaction and after each commit that edits a mapped file, and act on what it reports.
@@ -0,0 +1,15 @@
1
+ These places are mapped as keeping the principles held, each with the role its member gives it:
2
+
3
+ %{members}
4
+
5
+ A place keeps them held only through what triggers it: a hook, a timer or a reader. With the user, name which of
6
+ the keeping steps each one lacks: running `principles list-member-problems --short` at session start, after a
7
+ compaction and after each commit that edits a mapped file, and acting on what it reports. The members listed in
8
+ members_in_entry_files are the ones in an entry file. This tool writes none of the project's guidance.
9
+
10
+ Where a step is missing, the passage is one way to add it, at %{estimated_tokens} estimated tokens in every session
11
+ that loads the entry file it goes in.
12
+
13
+ Once the passage is placed, map it: %{command}
14
+
15
+ To map another place that runs a missing step, giving as STEP the step it runs and as TRIGGER what starts it: %{any_place}
@@ -0,0 +1,31 @@
1
+ Show the user the passage, which suits any entry file, and agree with them where it goes: an entry file that every
2
+ session of their agents loads. If a passage there already says all of it, map that one instead. If a member listed
3
+ in members_in_entry_files already says it, the passage is placed and mapped: go on to next_action. This tool writes
4
+ none of the project's guidance.
5
+
6
+ The first member need not be the passage: it can be any file or setting in the project that keeps the principles
7
+ in front of the agent, such as a timer of the project's own, or the committed setting that enables the plugin for
8
+ the team, its enabledPlugins line. Map it with a role that names, as STEP, the step it runs and, as TRIGGER, what
9
+ starts that step: a hook, a timer or a reader. Mapping it says only that the project names something to keep them
10
+ held; this principle's audit judges whether it does.
11
+
12
+ To map such a place: %{any_place}
13
+
14
+ Where the owner enables the plugin only at user scope, the project has nothing to map for it. Say so, and name the
15
+ two ways on: commit the project-scope enablement and map its line, or leave the "Set principles up first" line
16
+ standing.
17
+
18
+ Where only a reader enforces a step, with no hook or timer that runs it, say so in what you place.
19
+
20
+ Where the project says how a teammate gets `principles`, such as an install section or a setup note, link to it in
21
+ what you place. Say in a few words what `principles` is, so a teammate knows what the passage and any link lead to.
22
+ Where the project says nowhere how to get it, tell the user that a teammate who reads the passage cannot act on it
23
+ without that.
24
+
25
+ Where a passage the project already has carries one of the proposed passage's steps, leave that step out and map
26
+ that passage too, so each rule is said once, giving its file as PATH and its heading as HEADING: %{existing}
27
+
28
+ Once the passage is in the file, map it: %{command}
29
+
30
+ That command names the heading the passage is proposed under; where you placed it under another heading, give
31
+ --section the heading you placed it under.
@@ -0,0 +1,2 @@
1
+ Set principles up first, mapping a passage, a timer or the setting that enables the plugin as what keeps them held
2
+ between audits: %{command}
@@ -0,0 +1,4 @@
1
+ The passage asks its steps only where `principles` is installed, so a teammate without `principles` is told to do
2
+ nothing it cannot, but still loads its %{estimated_tokens} estimated tokens in every session that loads the entry
3
+ file. Nothing runs the steps for that teammate: the plugin's session-start hook reports only in sessions where the
4
+ plugin is enabled, and whether a teammate's sessions have it is something this tool cannot see.
@@ -0,0 +1,5 @@
1
+ %{findings}.%{without_waits_on}%{write_ups} %{returns} until a full audit decides %{them}.
2
+ %{when} list %{them}, then raise in one short message any waiting on the user or no one named. Judge by
3
+ context, such as git's user name, whether a named person is your user; if unsure, raise it. Do not raise any
4
+ waiting on someone else, or that you can see you raised in this conversation. To see whom %{each} waits on, run
5
+ %{command}
@@ -0,0 +1 @@
1
+ This line returns after each clear or compaction too
@@ -0,0 +1 @@
1
+ This line returns at each session start
@@ -0,0 +1 @@
1
+ Before the user's first task,
@@ -0,0 +1,71 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+
6
+ module Principles
7
+ # What this tool prints, built from domain values at print time. views/CLAUDE.md owns the boundary.
8
+ module Views
9
+ # The text this tool prints to guide the agent, kept in views/prompts/ under a folder for the
10
+ # workflow step that uses it. views/CLAUDE.md owns the layout. A prompt is Markdown wrapped for
11
+ # reading: single line breaks join into spaces, and a blank line separates paragraphs.
12
+ module Prompts
13
+ ROOT = File.join(__dir__, "prompts").freeze #: String
14
+
15
+ # A prompt's text, with each %{name} placeholder filled from values.
16
+ #: (String, **String) -> String
17
+ def self.text(name, **values) = Prompt.read(name).wrapped.filled(values)
18
+
19
+ # A prompt printed as Markdown, such as a command's --help: its lines stay as written, and each
20
+ # %{name} placeholder is filled from values.
21
+ #: (String, **String) -> String
22
+ def self.markdown(name, **values) = Prompt.read(name).filled(values)
23
+
24
+ # A prompt that shows a shape by example, as JSON data.
25
+ #: (String) -> untyped
26
+ def self.data(name)
27
+ JSON.parse(File.read(File.join(ROOT, "#{name}.json")))
28
+ end
29
+
30
+ # Every prompt name, relative to ROOT and without its extension.
31
+ #: () -> Array[String]
32
+ def self.names
33
+ Dir.glob("**/*.{md,json}", base: ROOT).map { |path| path.sub(/\.(md|json)\z/, "") }.sort
34
+ end
35
+ end
36
+
37
+ # One packaged prompt: its name and its text as written. It lives beside Prompts, so the views' one
38
+ # file-reading exception stays one file; give it its own file and spec if it grows rules of its own.
39
+ class Prompt
40
+ # The prompt packaged as name.md under Prompts::ROOT.
41
+ #: (String) -> Prompt
42
+ def self.read(name) = new(name, File.read(File.join(Prompts::ROOT, "#{name}.md")).strip)
43
+
44
+ #: (String, String) -> void
45
+ def initialize(name, text)
46
+ @name = name
47
+ @text = text
48
+ freeze
49
+ end
50
+
51
+ # The prompt wrapped for reading: single line breaks join into spaces, and a blank line separates
52
+ # paragraphs.
53
+ #: () -> Prompt
54
+ def wrapped
55
+ Prompt.new(@name, @text.split(/\n{2,}/).map { |paragraph| paragraph.gsub(/\s*\n\s*/, " ") }.join("\n\n"))
56
+ end
57
+
58
+ # The text with each placeholder filled. Text with no values is left as it is, since a prompt may hold a
59
+ # literal %, but one holding a placeholder is refused, so it never reaches the agent unfilled (#422).
60
+ #: (Hash[Symbol, String]) -> String
61
+ def filled(values)
62
+ return format(@text, **values) unless values.empty?
63
+
64
+ placeholder = @text[/%\{\w+\}/]
65
+ raise ArgumentError, "prompt #{@name} needs a value for #{placeholder}" if placeholder
66
+
67
+ @text
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,80 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "invocation"
5
+ require_relative "prompts"
6
+
7
+ module Principles
8
+ # What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
9
+ module Views
10
+ # A repoint of a principle's open findings' write-ups: its request and its result (D59).
11
+ class RepointResult
12
+ # What an accepted repoint did: the ids of the findings it repointed and of those it left where they point,
13
+ # and each other principle's open finding whose write-up cannot be found, with those principles (T16).
14
+ class Outcome
15
+ #: Array[String]
16
+ attr_reader :repointed, :unchanged
17
+ # Each as its principle and finding_id.
18
+ #: Array[Hash[String, String]]
19
+ attr_reader :not_found_elsewhere
20
+
21
+ #: (repointed: Array[String], unchanged: Array[String], not_found_elsewhere: Array[Hash[String, String]])
22
+ #| -> void
23
+ def initialize(repointed:, unchanged:, not_found_elsewhere:)
24
+ @repointed = repointed
25
+ @unchanged = unchanged
26
+ @not_found_elsewhere = not_found_elsewhere
27
+ freeze
28
+ end
29
+
30
+ # The other principles not_found_elsewhere names, each once.
31
+ #: () -> Array[String]
32
+ def principles_elsewhere = @not_found_elsewhere.map { |finding| finding.fetch("principle") }.uniq
33
+ end
34
+
35
+ #: (Invocation) -> void
36
+ def initialize(invocation)
37
+ @invocation = invocation
38
+ freeze
39
+ end
40
+
41
+ # findings are the open findings, each with its recorded_at and what list-open-findings says of its write-up.
42
+ #: (request_id: String, principle_id: String, revision: String?, findings: Array[Hash[String, untyped]])
43
+ #| -> Hash[String, untyped]
44
+ def request(request_id:, principle_id:, revision:, findings:)
45
+ repoints = findings.map do |finding|
46
+ { "finding_id" => finding["finding_id"], "recorded_at" => nil, "reason" => "" }
47
+ end
48
+ { "status" => "agent_judgement_required", "request_id" => request_id, "phase" => "repointing",
49
+ "context" => { "principle_id" => principle_id, "findings" => findings,
50
+ "question" => Prompts.text("repoint-write-ups/point-each-moved-write-up-at-its-new-place") },
51
+ "response_template" => { "request_id" => request_id, "basis" => { "revision" => revision },
52
+ "repoints" => repoints },
53
+ "answer_with" => @invocation.submit_answer(request_id) }
54
+ end
55
+
56
+ # The repoints were accepted, as outcome says, and file holds them.
57
+ #: (principle_id: String, file: String, outcome: Outcome) -> Hash[String, untyped]
58
+ def repointed(principle_id:, file:, outcome:)
59
+ { "status" => "write_ups_repointed", "principle_id" => principle_id, "repointed" => outcome.repointed,
60
+ "unchanged" => outcome.unchanged, "other_write_ups_not_found" => outcome.not_found_elsewhere,
61
+ "files_to_commit" => [file],
62
+ "next_action" => "Commit #{file}. After committing, this names no write-up of #{principle_id} it cannot " \
63
+ "find: #{@invocation.in_project("list-open-findings", principle_id, usage: "--short")}" \
64
+ "#{elsewhere(outcome.principles_elsewhere)}" }
65
+ end
66
+
67
+ private
68
+
69
+ # The request that repoints each other principle's write-ups, one per line, or nothing when there is none.
70
+ #: (Array[String]) -> String
71
+ def elsewhere(principle_ids)
72
+ return "" if principle_ids.empty?
73
+
74
+ commands = principle_ids.map { |id| "#{@invocation.in_project("start-audit", id, usage: "--write-ups")}\n" }
75
+ "\nWrite-ups of other principles cannot be found either, listed under other_write_ups_not_found. " \
76
+ "Check each, and repoint it with its own request:\n#{commands.join}"
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Principles
5
+ # What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
6
+ module Views
7
+ # One part of a judgement request beyond its members, such as the prior findings to decide (D35) or the members
8
+ # to check against the activation (#355): what the agent reads of it, its list and the instruction for it, and
9
+ # the slots it adds to the answer's template, which the request builds in where each belongs (D60).
10
+ class RequestPart
11
+ # What the agent reads of this part: its list, then the instruction for deciding it.
12
+ #: Hash[String, untyped]
13
+ attr_reader :shown
14
+ # The slots this part adds to the answer's template.
15
+ #: Hash[String, untyped]
16
+ attr_reader :slots
17
+
18
+ #: (shown: Hash[String, untyped], slots: Hash[String, untyped]) -> void
19
+ def initialize(shown:, slots:)
20
+ @shown = shown
21
+ @slots = slots
22
+ freeze
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "request_part"
5
+
6
+ module Principles
7
+ # What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
8
+ module Views
9
+ # A judgement request's parts beyond its members, in the order the agent reads them (D60).
10
+ class RequestParts
11
+ #: (Array[RequestPart]) -> void
12
+ def initialize(parts)
13
+ @parts = parts
14
+ freeze
15
+ end
16
+
17
+ # entries, with what each part shows added after them, in order.
18
+ #: (Hash[String, untyped]) -> Hash[String, untyped]
19
+ def shown_after(entries) = @parts.reduce(entries) { |all, part| all.merge(part.shown) }
20
+
21
+ # template, with each part's slots added after its own entries, in order.
22
+ #: (Hash[String, untyped]) -> Hash[String, untyped]
23
+ def slotted_after(template) = @parts.reduce(template) { |all, part| all.merge(part.slots) }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Principles
5
+ # What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
6
+ module Views
7
+ # One word of a printed command, as a shell reads it: as it is when it holds only characters no shell treats
8
+ # specially, else in single quotes, inside which a shell expands nothing. Ids, paths and headings come from
9
+ # project files anyone may have written (#227).
10
+ class ShellWord
11
+ # A word every common shell reads as it is: no quote, space, $, `, glob or redirection, and no = or #,
12
+ # which zsh can expand.
13
+ PLAIN = %r{\A[\w./:@%+,-]+\z}
14
+
15
+ #: (String) -> void
16
+ def initialize(value)
17
+ @value = value
18
+ freeze
19
+ end
20
+
21
+ #: () -> String
22
+ def to_s
23
+ return @value if PLAIN.match?(@value)
24
+
25
+ "'#{@value.gsub("'") { "'\\''" }}'"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Principles
5
+ # What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
6
+ module Views
7
+ # Text from a project file or an agent's answer, printed outside JSON with each control, format and separator
8
+ # character written as \uXXXX, as JSON output shows it, so a tab cannot split a field and an invisible character
9
+ # cannot hide (#227). cli.rb escapes printed JSON without control characters, since JSON already escapes them
10
+ # inside strings and its own newlines must stay; so the two are not one rule to fold together.
11
+ class VisibleText
12
+ #: (String) -> void
13
+ def initialize(text)
14
+ @text = text
15
+ freeze
16
+ end
17
+
18
+ #: () -> String
19
+ def to_s
20
+ @text.gsub(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/) do |character|
21
+ character.encode("UTF-16BE").unpack("n*").map { |unit| format("\\u%04x", unit) }.join
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end