@ethlete/agent-rules 0.1.0-next.3 → 0.1.0-next.31

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 (200) hide show
  1. package/AGENTS.md +28 -0
  2. package/CHANGELOG.md +480 -0
  3. package/CLAUDE.md +1 -0
  4. package/README.md +362 -29
  5. package/THIRD-PARTY-LICENSES.md +35 -0
  6. package/content/defaults.json +1 -1
  7. package/content/git-hooks/post-checkout.sh +10 -0
  8. package/content/git-hooks/pre-push.sh +5 -0
  9. package/content/hooks/context-warning.py +872 -110
  10. package/content/hooks/subagent-model-policy.py +194 -0
  11. package/content/mods/.claude-plugin/marketplace.json +11 -0
  12. package/content/mods/plugins/e2e-progress/.claude-plugin/plugin.json +6 -0
  13. package/content/mods/plugins/e2e-progress/hooks/hooks.json +1 -0
  14. package/content/mods/plugins/e2e-progress/hooks/register.tsx +442 -0
  15. package/content/mods/plugins/e2e-progress/tsconfig.json +3 -0
  16. package/content/mods/plugins/e2e-progress/types/index.d.ts +23 -0
  17. package/content/output-styles/ste-clarity.md +131 -0
  18. package/content/rules/agent-sessions-wake-up.md +11 -0
  19. package/content/rules/app-styling.md +66 -0
  20. package/content/rules/comments.md +4 -1
  21. package/content/rules/lint-and-format.md +7 -5
  22. package/content/rules/nx-layout.md +50 -0
  23. package/content/rules/reactive-state.md +1 -1
  24. package/content/rules/styling.md +9 -7
  25. package/content/rules/subagent-models.md +39 -0
  26. package/content/skills/agent-sessions/SKILL.md +81 -0
  27. package/content/skills/agent-sessions/agent-sessions.mjs +498 -0
  28. package/content/skills/angular-patterns/SKILL.md +30 -7
  29. package/content/skills/api-source/SKILL.md +156 -0
  30. package/content/skills/app-testing/SKILL.md +141 -0
  31. package/content/skills/codex-subagent/SKILL.md +90 -0
  32. package/content/skills/codex-subagent/codex-agent.mjs +229 -0
  33. package/content/skills/design-exploration/SKILL.md +687 -0
  34. package/content/skills/design-exploration/check-story.mjs +139 -0
  35. package/content/skills/design-exploration/shoot-template.mjs +61 -0
  36. package/content/skills/domain-modeling/ADR-FORMAT.md +47 -0
  37. package/content/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  38. package/content/skills/domain-modeling/SKILL.md +80 -0
  39. package/content/skills/e2e-triage/SKILL.md +80 -0
  40. package/content/skills/figma-export/SKILL.md +191 -0
  41. package/content/skills/figma-export/dump-figma-layers.py +83 -0
  42. package/content/skills/figma-export/dump-figma-svg.py +235 -0
  43. package/content/skills/figma-export/measure-template.mjs +87 -0
  44. package/content/skills/git-commit/SKILL.md +11 -7
  45. package/content/skills/git-flow/SKILL.md +87 -0
  46. package/content/skills/grill-with-docs/SKILL.md +13 -0
  47. package/content/skills/grilling/SKILL.md +51 -0
  48. package/content/skills/handoff/SKILL.md +125 -5
  49. package/content/skills/query/SKILL.md +165 -64
  50. package/content/skills/rxjs-signals/SKILL.md +33 -4
  51. package/content/skills/sdk-docs/SKILL.md +50 -14
  52. package/content/skills/sdk-local-build/SKILL.md +26 -8
  53. package/content/skills/sdk-local-build/sdk-local-baseline.mjs +64 -0
  54. package/content/skills/sdk-source/SKILL.md +37 -34
  55. package/content/skills/sdk-update/SKILL.md +103 -0
  56. package/content/skills/story-styling/SKILL.md +10 -8
  57. package/content/skills/styleguide/SKILL.md +12 -7
  58. package/content/skills/styleguide/assets.md +54 -0
  59. package/content/skills/styleguide/changesets.md +17 -0
  60. package/content/skills/styleguide/file-structure.md +73 -0
  61. package/content/skills/styleguide/lint-rule-lookup.md +51 -0
  62. package/content/skills/styleguide/storybook-structure.md +25 -0
  63. package/content/skills/theming/SKILL.md +50 -28
  64. package/content/skills/timetrack/SKILL.md +397 -0
  65. package/content/skills/verify-in-app/SKILL.md +107 -0
  66. package/migrations/app-styling-utilities.md +63 -0
  67. package/migrations/list-state-query-form.md +20 -0
  68. package/migrations/nx-layout.md +29 -0
  69. package/migrations/sdk-components-over-hand-built-ui.md +27 -0
  70. package/migrations/search-query-field.md +52 -0
  71. package/migrations.json +48 -0
  72. package/package.json +19 -3
  73. package/src/index.js +85 -30
  74. package/src/index.js.map +1 -1
  75. package/src/lib/cli-args.d.ts +9 -0
  76. package/src/lib/cli-args.js +48 -0
  77. package/src/lib/cli-args.js.map +1 -0
  78. package/src/lib/commitlint.d.ts +10 -0
  79. package/src/lib/commitlint.js +51 -0
  80. package/src/lib/commitlint.js.map +1 -0
  81. package/src/lib/config.d.ts +41 -5
  82. package/src/lib/config.js +117 -10
  83. package/src/lib/config.js.map +1 -1
  84. package/src/lib/filter.d.ts +2 -0
  85. package/src/lib/filter.js +4 -4
  86. package/src/lib/filter.js.map +1 -1
  87. package/src/lib/frontmatter.d.ts +2 -0
  88. package/src/lib/frontmatter.js +33 -5
  89. package/src/lib/frontmatter.js.map +1 -1
  90. package/src/lib/git-flow/build.d.ts +35 -0
  91. package/src/lib/git-flow/build.js +24 -0
  92. package/src/lib/git-flow/build.js.map +1 -0
  93. package/src/lib/git-flow/config.d.ts +59 -0
  94. package/src/lib/git-flow/config.js +50 -0
  95. package/src/lib/git-flow/config.js.map +1 -0
  96. package/src/lib/git-flow/index.d.ts +6 -0
  97. package/src/lib/git-flow/index.js +23 -0
  98. package/src/lib/git-flow/index.js.map +1 -0
  99. package/src/lib/git-flow/parse.d.ts +49 -0
  100. package/src/lib/git-flow/parse.js +300 -0
  101. package/src/lib/git-flow/parse.js.map +1 -0
  102. package/src/lib/git-flow/rename.d.ts +24 -0
  103. package/src/lib/git-flow/rename.js +70 -0
  104. package/src/lib/git-flow/rename.js.map +1 -0
  105. package/src/lib/git-flow/start.d.ts +49 -0
  106. package/src/lib/git-flow/start.js +57 -0
  107. package/src/lib/git-flow/start.js.map +1 -0
  108. package/src/lib/git-flow/validate.d.ts +34 -0
  109. package/src/lib/git-flow/validate.js +72 -0
  110. package/src/lib/git-flow/validate.js.map +1 -0
  111. package/src/lib/git-flow-command.d.ts +4 -0
  112. package/src/lib/git-flow-command.js +165 -0
  113. package/src/lib/git-flow-command.js.map +1 -0
  114. package/src/lib/git-flow-repair.d.ts +17 -0
  115. package/src/lib/git-flow-repair.js +165 -0
  116. package/src/lib/git-flow-repair.js.map +1 -0
  117. package/src/lib/git-flow-start.d.ts +20 -0
  118. package/src/lib/git-flow-start.js +140 -0
  119. package/src/lib/git-flow-start.js.map +1 -0
  120. package/src/lib/git.d.ts +64 -0
  121. package/src/lib/git.js +131 -0
  122. package/src/lib/git.js.map +1 -0
  123. package/src/lib/gitlab.d.ts +35 -0
  124. package/src/lib/gitlab.js +116 -0
  125. package/src/lib/gitlab.js.map +1 -0
  126. package/src/lib/index.d.ts +2 -0
  127. package/src/lib/index.js +26 -11
  128. package/src/lib/index.js.map +1 -1
  129. package/src/lib/migrate.js +6 -1
  130. package/src/lib/migrate.js.map +1 -1
  131. package/src/lib/output-style-command.d.ts +3 -0
  132. package/src/lib/output-style-command.js +69 -0
  133. package/src/lib/output-style-command.js.map +1 -0
  134. package/src/lib/output-style.d.ts +38 -0
  135. package/src/lib/output-style.js +134 -0
  136. package/src/lib/output-style.js.map +1 -0
  137. package/src/lib/owned-paths.js +27 -3
  138. package/src/lib/owned-paths.js.map +1 -1
  139. package/src/lib/package-runner.d.ts +4 -0
  140. package/src/lib/package-runner.js +86 -0
  141. package/src/lib/package-runner.js.map +1 -0
  142. package/src/lib/plain-text.d.ts +9 -0
  143. package/src/lib/plain-text.js +22 -0
  144. package/src/lib/plain-text.js.map +1 -0
  145. package/src/lib/plan.d.ts +6 -6
  146. package/src/lib/plan.js +164 -40
  147. package/src/lib/plan.js.map +1 -1
  148. package/src/lib/prompt.d.ts +8 -0
  149. package/src/lib/prompt.js +35 -0
  150. package/src/lib/prompt.js.map +1 -0
  151. package/src/lib/render.d.ts +25 -2
  152. package/src/lib/render.js +43 -10
  153. package/src/lib/render.js.map +1 -1
  154. package/src/lib/sessions-command.d.ts +4 -0
  155. package/src/lib/sessions-command.js +16 -0
  156. package/src/lib/sessions-command.js.map +1 -0
  157. package/src/lib/sync.d.ts +0 -1
  158. package/src/lib/sync.js +30 -17
  159. package/src/lib/sync.js.map +1 -1
  160. package/src/lib/targets/agents-skills.js +1 -1
  161. package/src/lib/targets/agents-skills.js.map +1 -1
  162. package/src/lib/targets/claude-hooks.d.ts +3 -23
  163. package/src/lib/targets/claude-hooks.js +22 -86
  164. package/src/lib/targets/claude-hooks.js.map +1 -1
  165. package/src/lib/targets/claude-mods.d.ts +20 -0
  166. package/src/lib/targets/claude-mods.js +47 -0
  167. package/src/lib/targets/claude-mods.js.map +1 -0
  168. package/src/lib/targets/claude.js +2 -3
  169. package/src/lib/targets/claude.js.map +1 -1
  170. package/src/lib/targets/codex-hooks.d.ts +12 -0
  171. package/src/lib/targets/codex-hooks.js +35 -0
  172. package/src/lib/targets/codex-hooks.js.map +1 -0
  173. package/src/lib/targets/codex.js +4 -4
  174. package/src/lib/targets/codex.js.map +1 -1
  175. package/src/lib/targets/copilot.js +4 -4
  176. package/src/lib/targets/copilot.js.map +1 -1
  177. package/src/lib/targets/cursor.js +3 -3
  178. package/src/lib/targets/cursor.js.map +1 -1
  179. package/src/lib/targets/git-hooks.d.ts +25 -0
  180. package/src/lib/targets/git-hooks.js +71 -0
  181. package/src/lib/targets/git-hooks.js.map +1 -0
  182. package/src/lib/targets/hooks-shared.d.ts +60 -0
  183. package/src/lib/targets/hooks-shared.js +130 -0
  184. package/src/lib/targets/hooks-shared.js.map +1 -0
  185. package/src/lib/targets/mcp.d.ts +16 -0
  186. package/src/lib/targets/mcp.js +68 -0
  187. package/src/lib/targets/mcp.js.map +1 -0
  188. package/src/lib/targets/shared.d.ts +1 -9
  189. package/src/lib/targets/shared.js +4 -8
  190. package/src/lib/targets/shared.js.map +1 -1
  191. package/src/lib/timetrack-command.d.ts +11 -0
  192. package/src/lib/timetrack-command.js +1063 -0
  193. package/src/lib/timetrack-command.js.map +1 -0
  194. package/src/lib/timetrack-snapshot.d.ts +55 -0
  195. package/src/lib/timetrack-snapshot.js +120 -0
  196. package/src/lib/timetrack-snapshot.js.map +1 -0
  197. package/src/lib/timetrack.d.ts +561 -0
  198. package/src/lib/timetrack.js +279 -0
  199. package/src/lib/timetrack.js.map +1 -0
  200. package/content/skills/styleguide/STYLEGUIDE.md +0 -520
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: ste-clarity
3
+ description: Write all prose in ASD-STE100 Simplified Technical English — approved words, simple verb forms, active voice, one idea per sentence.
4
+ keep-coding-instructions: true
5
+ ---
6
+
7
+ # ASD-STE100 output style
8
+
9
+ Write every sentence you show the user in Simplified Technical English, as specified
10
+ by ASD-STE100. Clarity comes first. Never sacrifice technical accuracy for brevity.
11
+
12
+ ## Scope
13
+
14
+ Apply STE to your own prose: answers, explanations, plans, summaries, commit
15
+ messages, and pull request text.
16
+
17
+ Do not apply STE to:
18
+
19
+ - Code, identifiers, file paths, and command names.
20
+ - Quoted material: error messages, log lines, command output, and text from files.
21
+ Copy these exactly. Never rewrite a quote to make it simpler.
22
+ - Text the user asks you to write in a different style.
23
+
24
+ Markdown is still available. Use code blocks, and use `file.ts:42` references.
25
+
26
+ ## Words
27
+
28
+ 1. Use the most common, shortest word that has one clear meaning.
29
+ 2. Use one word for one meaning. Do not use synonyms for the same thing. If you
30
+ write "flag" for a variable, do not later call it a "switch" or an "option".
31
+ 3. Use one meaning for one word. Do not use "close" for both a state and an action
32
+ if this can confuse the reader.
33
+ 4. Technical names are permitted. Use the exact name from the code or the domain.
34
+ 5. Do not use slang, idioms, or figures of speech. "The build blew up" is wrong.
35
+ "The build failed" is correct.
36
+ 6. Do not use "etc." Complete the list, or write "for example" and give two items.
37
+ 7. Do not use a noun as a verb. Write "make a request", not "request it", when
38
+ "request" is a name in the code.
39
+
40
+ Prefer the word on the right:
41
+
42
+ | Not approved | Use |
43
+ | ------------------------ | ----------------- |
44
+ | utilize, employ | use |
45
+ | initiate, commence | start |
46
+ | terminate | stop, end |
47
+ | perform, execute | do, run |
48
+ | modify | change |
49
+ | indicate | show |
50
+ | ascertain, determine | find, find out |
51
+ | assist, aid | help |
52
+ | attempt | try |
53
+ | require | need |
54
+ | sufficient | enough |
55
+ | additional | more |
56
+ | numerous, multiple | many |
57
+ | approximately | about |
58
+ | currently, presently | now |
59
+ | prior to | before |
60
+ | subsequent to, following | after |
61
+ | in order to | to |
62
+ | due to the fact that | because |
63
+ | via | with, by, through |
64
+ | such as | for example |
65
+ | in the event that | if |
66
+ | at this point in time | now |
67
+
68
+ This table is a guide, not the full ASD-STE100 Dictionary. The Dictionary holds about
69
+ 900 approved words, each with one approved part of speech and one approved meaning.
70
+ When you do not know if a word is approved, choose the shortest common word that has
71
+ one clear meaning.
72
+
73
+ ## Verbs
74
+
75
+ 1. Use only these verb forms: the infinitive, the imperative, the simple present, the
76
+ simple past, the simple future, and the past participle as an adjective.
77
+ 2. Do not use complex tenses. Write "I changed the config", not "I have changed the
78
+ config".
79
+ 3. Do not use "-ing" forms, unless the form is part of a technical name, for example
80
+ "a logging module".
81
+ 4. Use the active voice. Write "the parser drops the field", not "the field is dropped
82
+ by the parser". Use the passive voice only when the actor is unknown or does not
83
+ matter.
84
+ 5. Do not leave out a verb to make a sentence shorter.
85
+
86
+ ## Noun phrases
87
+
88
+ 1. Do not build a cluster of more than three nouns. Break up "user account balance
89
+ sync failure" as "a failure in the sync of the user account balance".
90
+ 2. Add articles ("a", "the") where they help the reader.
91
+
92
+ ## Sentences
93
+
94
+ 1. Instructions: 20 words maximum.
95
+ 2. Descriptions: 25 words maximum.
96
+ 3. One idea per sentence. One instruction per sentence.
97
+ 4. A paragraph holds 6 sentences maximum, and covers one topic.
98
+ 5. Put a condition at the start of the sentence, before the instruction. Write "If the
99
+ sync fails, restart the server".
100
+ 6. Use connecting words such as "however", "therefore", and "then" to show the link
101
+ between sentences.
102
+ 7. Use a vertical list when the content has more than three parallel parts. Do not use
103
+ a list to give structure to a single idea.
104
+
105
+ ## Procedures
106
+
107
+ 1. Use the imperative for each step. Write "Open the file", not "You should open the
108
+ file" or "We can open the file".
109
+ 2. Number the steps in the order the user must do them.
110
+ 3. Give the result after the action, if the result is not obvious.
111
+
112
+ ## Warnings
113
+
114
+ 1. Put a warning or a caution before the step it applies to, never after.
115
+ 2. Start the warning with a clear command. Write "Do not run this on the production
116
+ database. The command deletes all rows."
117
+ 3. State the consequence in a separate, simple sentence.
118
+
119
+ ## Punctuation
120
+
121
+ 1. Do not use a slash to mean "and" or "or". Write "the date or the payee".
122
+ 2. Do not use parentheses for information the reader needs. Put it in its own sentence.
123
+ 3. Do not use a dash to join two thoughts. Use two sentences.
124
+ 4. Use a hyphen only to make a compound word clear.
125
+
126
+ ## When STE and accuracy conflict
127
+
128
+ Accuracy wins. If a simple word would hide a real distinction, use the exact term and
129
+ define it once in a short sentence. Never simplify a claim about what the code does.
130
+ Keep the difference between what you verified and what you assume: write "I ran the
131
+ tests and they passed" or "I did not run the tests", not a sentence that blurs the two.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: agent-sessions-wake-up
3
+ description: A prompt that says "New mailbox message for <name>" means run the inbox command in it and act on the result; read the agent-sessions skill before you edit a file another agent may edit.
4
+ kind: rule
5
+ scope: both
6
+ ---
7
+
8
+ ## Agent sessions
9
+
10
+ If a prompt says `New mailbox message for <name>`, run the `inbox` command in that prompt and act on
11
+ the messages. Before you edit a file that another agent may edit, read {% skill:agent-sessions %}.
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: app-styling
3
+ description: App components are styled with Tailwind utilities in their templates; app CSS stays out of @layer components; the SDK needs a 10px rem root; hardcoded colours are never primary values.
4
+ kind: rule
5
+ scope: consumer
6
+ requires: ['@ethlete/core']
7
+ ---
8
+
9
+ ## Styling
10
+
11
+ Every component in this workspace (views, pages, shells, shared UI in `libs/`) is laid out
12
+ and styled with **Tailwind utility classes in its template**, including the colour utilities
13
+ the app's theme provides: the generated SDK theme utilities (`bg-et-surface-bg`,
14
+ `border-et-surface-border`, `text-et-<theme>`) where the app generates them, or the palette its
15
+ Tailwind config defines. Do not
16
+ invent a BEM class system, and do not write a `.css` file for layout, spacing or
17
+ typography a utility expresses. Every app component sets `encapsulation: ViewEncapsulation.None`,
18
+ as the `require-view-encapsulation-none` lint rule requires. Its CSS is then global, so give the
19
+ component a host class (`host: { class: 'app-player-card' }`) and scope every selector under it,
20
+ the way SDK components scope theirs under their `et-` classes. Never write a bare element or
21
+ unprefixed class selector in a component stylesheet.
22
+
23
+ In an existing repo, convert a component's styles whenever you change any of its files (class,
24
+ template, template-bound logic or CSS), not only its styles; if the conversion is large, ask the
25
+ user first. A legacy component that relies on emulated encapsulation keeps it until its CSS is
26
+ scoped under a host class: without that scope, `ViewEncapsulation.None` leaks its CSS into every
27
+ view.
28
+
29
+ If the repo as a whole breaks this section (global classes in `styles.css`, hardcoded colours),
30
+ tell the user once at first contact, with the size of the conversion (files, classes, hardcoded
31
+ colours), and record it as owed work in the plan or handoff. Never skip it silently. This holds
32
+ for a deviation from any rule here: report it once and record it.
33
+
34
+ Write CSS only for what utilities cannot express. With Tailwind 4, keep that CSS **unlayered**
35
+ or in `@layer utilities` — never in `@layer components`, and that includes the global
36
+ stylesheet. SDK component styles are injected into `@layer components` at runtime, after your
37
+ stylesheet, so an app rule in the same layer ties on layer and loses on source order. With
38
+ Tailwind 3, `@layer` is a Tailwind directive that emits unlayered CSS, so app CSS already beats
39
+ the SDK's layered styles.
40
+
41
+ To change an SDK component's look, set its `--et-*` tokens first (documented per
42
+ component), then use a utility class or unlayered CSS on the element — see "Overriding
43
+ component styles" in the docs site's components overview.
44
+
45
+ The SDK sizes everything in `rem` on a **10px root**: the app's global stylesheet must set
46
+ `html { font-size: 62.5%; }`. Without it every SDK control renders 1.6× too large. With it,
47
+ `1rem` is `10px`, so the app's own `rem` values stay easy to read.
48
+
49
+ The 10px root also shrinks every rem-based Tailwind scale to 62.5% of its nominal size (1.6×
50
+ smaller): `p-4` is 10px instead of 16px, and `max-w-3xl` is 480px instead of 768px. Keep the
51
+ spacing scale on its 4px step: with Tailwind 4, set `--spacing: 0.4rem` in the app's `@theme`,
52
+ as the SDK's own Storybook does; with Tailwind 3, redefine `theme.spacing` in
53
+ `tailwind.config`. In an app that already uses utilities without it, the change rescales every
54
+ view: tell the user rather than make it. Redefine any other rem scale the app uses (text,
55
+ container, radius) the same way, or use px where a size matters. Breakpoints are not affected:
56
+ a media query's `rem` ignores the root font size.
57
+
58
+ **Never use a hardcoded colour as the primary value.** Backgrounds, text, borders and
59
+ interaction states resolve from the app's theme: the SDK surface and colour tokens
60
+ (`--et-surface-*-solid`, `--et-theme-color-*`) and their generated utilities, or the palette
61
+ the app's Tailwind config defines. Never write an arbitrary colour value such as
62
+ `bg-[#1a1a1a]` in a template. A static fallback inside `var(--token, <fallback>)` is
63
+ permitted, but not required.
64
+
65
+ Theme **names** (`brand`, `danger`, `dark-elevated`, …) are registered by this app; the SDK
66
+ ships none. Semantic colours resolve by theme `type` (e.g. `injectSemanticColorTheme('error')`).
@@ -20,6 +20,8 @@ smaller function, or a type; fix that instead of narrating it.
20
20
  limitation) and linking it where a link exists, so the next reader can tell when it may go.
21
21
  4. **Public API JSDoc** — what it does and how to call it, on something a lib actually
22
22
  exports. One or two sentences. Not internals, not history, not why it is shaped that way.
23
+ In an application nothing is public API unless it lives in a shared lib other projects
24
+ import, so this case rarely applies to app code.
23
25
 
24
26
  Nothing else qualifies. Not "this is subtle", not "worth noting", not a heading over a group
25
27
  of members, not a summary of the function underneath it.
@@ -43,7 +45,8 @@ years.
43
45
  annotation, a factory instead of a literal, a helper moved into its own file. The type, the
44
46
  annotation and the import already say what happens.
45
47
  - **Migration narration** — "moved here from X", "used to be a tuple", "so Y no longer pulls
46
- Z", "renamed for clarity". Git knows; the next reader does not care.
48
+ Z", "renamed for clarity", "see ADR-0012". Git and the ADR index know; the next reader does
49
+ not care.
47
50
  - **The same explanation at every call site.** Explain a pattern once where it is defined (the
48
51
  helper's JSDoc, the lint rule's message, the guide) and let every use site stay silent.
49
52
  - **Commented-out code.**
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lint-and-format
3
- description: Run lint with --fix before fixing anything by hand, and format every edited file.
3
+ description: Run lint with --fix before fixing anything by hand, and format every edited source file Prettier supports.
4
4
  kind: rule
5
5
  scope: both
6
6
  vars: [lintCommand, lintFixCommand, formatCommand]
@@ -12,14 +12,16 @@ Run lint with `--fix` — most styleguide rules in `@ethlete/eslint-plugin` ship
12
12
  so let them do the work before correcting anything by hand:
13
13
 
14
14
  ```bash
15
- {%lintFixCommand%} # auto-fixes first (case, ordering, $ suffix, metadata, …)
15
+ {%lintFixCommand%} # auto-fixes first (case, ordering, metadata, …); rename to the $ suffix by hand
16
16
  {%lintCommand%} # then re-run to see what needs a manual fix
17
17
  ```
18
18
 
19
- For the judgment calls lint cannot enforce — signals vs RxJS, templates, lifecycle and DI
20
- patterns — see {%skill:styleguide%}.
19
+ For judgment calls lint cannot enforce, load the repository's focused guidance for the
20
+ code you are changing.
21
21
 
22
- After editing any file, format it before wrapping up:
22
+ Format every edited Prettier-supported source file before wrapping up, in one call over all of
23
+ them, not one call per file. Do not send binary,
24
+ generated, or unsupported files to this command:
23
25
 
24
26
  ```bash
25
27
  {%formatCommand%}
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: nx-layout
3
+ description: Nx workspace layout - thin apps, feature code in libs grouped by kind, path-mirroring aliases, scope tags.
4
+ kind: rule
5
+ scope: consumer
6
+ requires: ['nx']
7
+ ---
8
+
9
+ ## Nx workspace layout
10
+
11
+ Apps are thin shells. All feature code lives in libs, grouped by kind, not by Nx type:
12
+
13
+ ```text
14
+ apps/<app>/src/app/ app.component.ts, app.config.ts, app.routes.ts only
15
+ libs/
16
+ domain/<app>/ one lib per app
17
+ src/lib/<feature>/ views, components, services, <feature>.routes.ts
18
+ src/lib/shared/ code shared by the app's features (optional)
19
+ queries/ query clients and creators, one folder per backend
20
+ types/ API models and shared types
21
+ uikit/ app-agnostic presentational components
22
+ theme/ surface and colour themes
23
+ env/ environment.ts, environment.production.ts
24
+ assets/ fonts, icons, images
25
+ ```
26
+
27
+ - Each feature folder exports its own `<FEATURE>_ROUTES`, re-exported from the lib's
28
+ `src/index.ts`. `app.routes.ts` only lazy-loads them:
29
+ `loadChildren: () => import('@acme/domain/admin').then((m) => m.USERS_ROUTES)`.
30
+ - Split a feature into its own lib (`libs/domain/<app>/<feature>`) only for a concrete
31
+ reason, such as size or build time, and name that reason to the user.
32
+ Never put features, queries, shared UI or theme in the app project.
33
+ - Do not add Nx `feature/ui/data-access/util` folders or `type:*` tags.
34
+ - Every lib has `src/index.ts` and explicit `build` (`@nx/angular:ng-packagr-lite`), `lint`
35
+ and `test` targets in `project.json`. Keep `plugins: []` in `nx.json`.
36
+ - Alias = path with slashes: `@acme/domain/admin`, `@acme/queries`, `@acme/types`,
37
+ `@acme/uikit`, `@acme/env`. Project name = path with dashes (`domain-admin`).
38
+ Component `prefix` = the repo abbreviation.
39
+ - Tag every project with one `scope:*`: `scope:<app>` for an app and its domain libs,
40
+ `scope:core` for env and types, plus `scope:queries`, `scope:uikit`, `scope:theme`.
41
+ `@nx/enforce-module-boundaries` with `enforceBuildableLibDependency: true` lets
42
+ `scope:<app>` depend on itself and the shared scopes, never on another app.
43
+ - A backend in the same workspace is an app in `apps/` with its libs in
44
+ `libs/domain/<name>-api`. Ban `@angular/*` in backend scopes and `@nestjs/*` in frontend
45
+ scopes with `bannedExternalImports`.
46
+ - Environment config lives only in `libs/env`, never hardcoded in a query client.
47
+
48
+ This is the layout for new workspaces and new code. Do not restructure the folders, projects
49
+ and tags of an existing workspace that deviates from it unless the user asks. This covers the
50
+ workspace layout only: every other rule still applies to the code you touch.
@@ -12,4 +12,4 @@ scope: both
12
12
  - **Bridge, don't copy.** Cross the boundary with `toSignal()` / `toObservable()`, never by
13
13
  `.subscribe()`-ing and assigning the value somewhere.
14
14
 
15
- Subscriptions, effects, and the traps in each direction: {%skill:rxjs-signals%}.
15
+ For subscriptions and effects, load the repository's focused reactive-state guidance.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: styling
3
- description: Component CSS is plain CSS in @layer components, and every colour comes from a theme token.
3
+ description: Component CSS is plain CSS in @layer components, and hardcoded colours are never primary values.
4
4
  kind: rule
5
- scope: both
5
+ scope: sdk
6
6
  requires: ['@ethlete/core']
7
7
  ---
8
8
 
@@ -26,10 +26,12 @@ utility can win.
26
26
  rule, so source order decides. Leave interaction states (`:hover`, `:focus-visible`,
27
27
  `:active`) bare so they escalate and win.
28
28
 
29
- **Never hardcode a colour.** Backgrounds, text, borders and interaction states all resolve
30
- from the surface and colour theming tokens (`--et-surface-*-solid`, `--et-theme-color-*`) —
31
- see {%skill:theming%}.
29
+ **Never use a hardcoded colour as the primary value.** Backgrounds, text, borders and
30
+ interaction states resolve from the surface and colour theming tokens
31
+ (`--et-surface-*-solid`, `--et-theme-color-*`). A static fallback inside
32
+ `var(--token, <fallback>)` is permitted, but not required.
32
33
 
33
34
  Theme **names** (`brand`, `danger`, `dark-elevated`, …) are registered by the application;
34
- the SDK ships none. Never hardcode a theme-name union in a type, a doc or an example —
35
- semantic colours resolve by theme `type` (e.g. `injectErrorTheme()`).
35
+ the SDK ships none. Never hardcode them as an SDK-defined union or reusable API contract.
36
+ If an app-specific example names one, label it as belonging to that app. Semantic colours
37
+ resolve by theme `type` (e.g. `injectSemanticColorTheme('error')`).
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: subagent-models
3
+ description: A subagent's model is an explicit choice on every call - haiku for lookups and small specified jobs, sonnet for scoped work, opus for hard work, fable for judgment.
4
+ kind: rule
5
+ scope: both
6
+ ---
7
+
8
+ ## Delegating: name the subagent's model
9
+
10
+ A subagent spawned without a `model` runs on the model leading the session, so an expensive
11
+ model ends up doing every small job it delegates. **Set `model` on every call**, matched to the
12
+ task:
13
+
14
+ | Model | The work it fits |
15
+ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | `haiku` | Lookups and small, fully specified jobs: grep, find, read and summarize files or a CI log, run a command and report, a mechanical edit in named files. Haiku 5.5 does these well. |
17
+ | `sonnet` | Scoped work with a clear target: a fix in a named file, a spec, a docs page, a lint cleanup, research that needs reasoning. Sonnet 5.5 is close to opus here and costs less. |
18
+ | `opus` | Hard work: a bug with no known cause, a change across many files, a review of a diff, and any task sonnet did not finish. |
19
+ | `fable` | Judgment-heavy work: planning, design, cross-cutting review, leading other subagents. The most expensive of the four, so ask the user before picking it. |
20
+
21
+ Effort follows the prompt, not a parameter: scope the prompt to one question, name what "done"
22
+ means, and say "keep it brief" for a lookup. Two calls need no `model` of their own - a named
23
+ agent type carries the model and reasoning effort its own definition sets, and a fork always
24
+ inherits the parent's model.
25
+
26
+ A subagent starts cold: it loads the full start context (about 50k tokens) before its first step,
27
+ and measured subagents cost as much as the sessions that spawn them. Do a lookup of a few tool
28
+ calls yourself. Give each subagent one large slice, not several small ones.
29
+
30
+ A subagent has the same context budget as the session, measured on its own transcript, and the
31
+ context-warning hook tells it to hand back at the critical tier. Size each prompt to fit: one
32
+ slice of work, the files it needs named, and "keep your context small - no whole big files".
33
+ Work that will not fit goes to several subagents in sequence, a fresh one per slice; a subagent
34
+ that hands back early names its remaining steps, which become the next one's prompt.
35
+
36
+ A subagent does not have to be a Claude one. Delegate to a Codex agent where another model
37
+ family would answer better - a second opinion, a review of your own diff, a bug hunt your own
38
+ reading failed - and whenever the Claude usage limit is close, because a Codex run does not draw
39
+ on it. Read {%skill:codex-subagent%} first.
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: agent-sessions
3
+ description: Run agents in tmux sessions of one checkout, message them, wake idle ones, restart a session with a prompt, and claim paths so two agents do not overwrite each other. Read before you edit a shared file while another agent may be active, and when the user says "mailbox", "coordinate with the other agent", "claim a file", "hand off to the other agent", or "restart the session".
4
+ kind: skill
5
+ scope: both
6
+ ---
7
+
8
+ # Agent sessions
9
+
10
+ One script, {%resource:agent-sessions.mjs%}, does three jobs for the agents of one checkout:
11
+
12
+ - **Sessions.** It runs each agent in a `tmux` session, and it can clear a session and start it with a prompt.
13
+ - **Messages.** Agents send each other messages through an append-only JSON-lines file, the mailbox. A dispatcher wakes an idle agent.
14
+ - **Claims.** An agent announces the paths it edits, so two agents do not overwrite each other.
15
+
16
+ Below, `<skill-dir>` is the directory this file sits in, and `<name>` is your own sender name. Where
17
+ the `ethlete-agents` package is a dependency, `npx ethlete-agents sessions <command>` runs the same
18
+ script, so you do not need `<skill-dir>`. The older name `npx ethlete-agents mailbox` works too.
19
+
20
+ ```bash
21
+ node <skill-dir>/agent-sessions.mjs run <name> <command...>
22
+ node <skill-dir>/agent-sessions.mjs up <name>[=<command>]...
23
+ node <skill-dir>/agent-sessions.mjs restart <name> [--after <seconds>] <prompt...>
24
+ node <skill-dir>/agent-sessions.mjs down [<name>...]
25
+ node <skill-dir>/agent-sessions.mjs shell-install [<agent>...] [--file <path>] [--remove] [--dry-run]
26
+ node <skill-dir>/agent-sessions.mjs shell-init [<agent>...]
27
+ node <skill-dir>/agent-sessions.mjs send <name> [--to <agent>] '<message>'
28
+ node <skill-dir>/agent-sessions.mjs inbox <name> [--wait <seconds>]
29
+ node <skill-dir>/agent-sessions.mjs read [--last <n>] [--all]
30
+ node <skill-dir>/agent-sessions.mjs watch <name>
31
+ node <skill-dir>/agent-sessions.mjs dispatch
32
+ node <skill-dir>/agent-sessions.mjs claim <name> <path...> [--ttl <hours>] [--force]
33
+ node <skill-dir>/agent-sessions.mjs release <name> [path...]
34
+ node <skill-dir>/agent-sessions.mjs claims
35
+ ```
36
+
37
+ ## Quick start for a person
38
+
39
+ Nothing runs until you start it, so a person who does not use this does nothing. To try it:
40
+
41
+ 1. Run `node <skill-dir>/agent-sessions.mjs shell-install`. It adds one function per agent to your shell file.
42
+ 2. Open a new terminal. In the repo, type `claude` or `codex` as usual. The function starts the agent in a `tmux` session and starts the dispatcher.
43
+ 3. Ask one agent to message the other. An idle agent wakes when a message carries `--to <agent>`.
44
+ 4. Run `node <skill-dir>/agent-sessions.mjs down` to stop the dispatcher. Run `shell-install --remove` to undo step 1.
45
+
46
+ ## Sessions
47
+
48
+ `run <name> <command...>` starts the command in the `tmux` session `<name>@<repo>`, or attaches if it runs already. It also starts the dispatcher when none runs. Session names carry the repo name, so `codex` in two repos never collides. If that session has a terminal attached already, `run` starts `<name>-2`, then `<name>-3`, and so on. A detached session is attached again. So a second `claude` terminal gets its own agent.
49
+
50
+ `up codex=codex gemini=gemini` starts a detached `tmux` session per agent, named like its sender name, and runs the command in it. It also starts a session named `mailbox-dispatch` that runs `dispatch`. A running session is left alone. Attach to a session with `tmux attach -t <name>`. Detach with `Ctrl-b`, then `d`. The session and its agent keep running. Use `down` to stop the dispatcher and the named sessions.
51
+
52
+ `restart <name> <prompt...>` types the clear command (`/clear`, or `/new` for a `codex` name) and then the prompt into the session `<name>@<repo>`, no sooner than `--after` seconds (default 5). It waits until that session ended its turn and its prompt holds no typed text, and gives up after 30 minutes. After the clear, a new turn does not hold the prompt back: a message can wake the fresh session, and Claude Code queues input typed during a turn. Only typed text in its prompt holds the prompt back. After 60 seconds of typed text, it saves the prompt to `.ethlete/restart.prompt.<session>.txt` and logs why in `.ethlete/restart.log`. The command returns at once, so end your turn after it. An agent uses it to clear itself and resume from its saved work state. It refuses any session other than the caller's own (from `$TMUX_PANE`), and the error names the caller's own sender name. Background commands of the old session still report into the new one.
53
+
54
+ `shell-install` writes one shell function per agent into `~/.zshrc` or `~/.bashrc`, between two marker lines. A second run replaces the block, and `--remove` deletes it. Use `--file` for another startup file and `--dry-run` to preview. After a new terminal opens, typing `claude` or `codex` in a repo with this skill runs the agent through `run`. Elsewhere the function starts the plain command. Run `shell-install` only when the user asks: it changes a file the user owns. `shell-init` prints the same functions without writing a file.
55
+
56
+ Choose a `<name>` that no other agent uses, for example `agent-a` or `agent-b`. Two sessions with one name look like one agent.
57
+
58
+ ## Messages
59
+
60
+ The mailbox file is `.ethlete/mailbox.jsonl` in the git root. The first write also creates `.ethlete/.gitignore`, so the file stays out of git. Set `AGENT_MAILBOX` to use another path. For two Claude Code sessions, the `SendMessage` tool is the better channel. The mailbox is for agents that cannot reach each other directly.
61
+
62
+ An idle agent cannot read the mailbox. One `dispatch` process outside every agent fixes this. It polls the mailbox for free. When a message carries `--to <agent>`, it waits a short grace period and then, if the agent has not read the message, types a wake-up line into the `tmux` session `<agent>@<repo>`, or a session named only `<agent>`. The agent then runs `inbox` and acts. A message without `--to` wakes nobody.
63
+
64
+ If the prompt of the agent holds typed text, the dispatcher waits until that text is sent or cleared. It checks again every 2 seconds. An open menu, for example a permission dialog, also makes it wait. If the agent is in the middle of a turn, the wake-up line waits as its next prompt. An agent in a `tmux` session does not need the `--wait` loop, which costs a turn at every timeout. If you wait for an answer in a session without `tmux`, run `inbox <name> --wait 120`: it blocks until a message arrives or 120 seconds pass. If it prints "No new messages.", run it again. A background `--wait` ends after one message, so it is not a lasting watch.
65
+
66
+ - `inbox` keeps one cursor per sender name, so it never repeats a message. The first call shows the last 20.
67
+ - `read` shows the last 20 messages. Use `--all` for the full history.
68
+ - `send` with no message reads it from standard input, so a long message needs no shell quoting.
69
+ - `watch` is optional. It runs until you stop it. In Claude Code, start it with the `Monitor` tool, so a new message wakes the session. Without such a feature, rely on `inbox`.
70
+ - Never rewrite or truncate the file. Only the script appends to it.
71
+ - Keep credentials and personal data out of the mailbox.
72
+
73
+ ## Claims
74
+
75
+ 1. At the start of a task, run `claims` and `inbox`. They show what other agents hold and said.
76
+ 2. Before you edit a file, run `claim` with the exact paths. A directory path claims everything below it. `claim` also prints the messages you have not seen yet.
77
+ 3. If `claim` reports a conflict, do not edit. Run `send` to ask the holder for a handoff, then wait.
78
+ 4. After each larger step, run `inbox` again. Most agents cannot wake on new output, so you must pull messages yourself.
79
+ 5. When you finish, run `release`. A claim also expires after 4 hours, or after `--ttl` hours.
80
+
81
+ A claim is advisory, not a lock. `--force` claims over another agent: use it only after the holder agreed. Silence is not approval. Acknowledge each handoff in words. No agent starts automatically. The user starts each one.