agent-notes 2.0.4__py3-none-any.whl

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 (162) hide show
  1. agent_notes/VERSION +1 -0
  2. agent_notes/__init__.py +1 -0
  3. agent_notes/__main__.py +4 -0
  4. agent_notes/cli.py +348 -0
  5. agent_notes/commands/__init__.py +27 -0
  6. agent_notes/commands/_install_helpers.py +262 -0
  7. agent_notes/commands/build.py +170 -0
  8. agent_notes/commands/doctor.py +112 -0
  9. agent_notes/commands/info.py +95 -0
  10. agent_notes/commands/install.py +99 -0
  11. agent_notes/commands/list.py +169 -0
  12. agent_notes/commands/memory.py +430 -0
  13. agent_notes/commands/regenerate.py +152 -0
  14. agent_notes/commands/set_role.py +143 -0
  15. agent_notes/commands/uninstall.py +26 -0
  16. agent_notes/commands/update.py +169 -0
  17. agent_notes/commands/validate.py +199 -0
  18. agent_notes/commands/wizard.py +720 -0
  19. agent_notes/config.py +154 -0
  20. agent_notes/data/agents/agents.yaml +352 -0
  21. agent_notes/data/agents/analyst.md +45 -0
  22. agent_notes/data/agents/api-reviewer.md +47 -0
  23. agent_notes/data/agents/architect.md +46 -0
  24. agent_notes/data/agents/coder.md +28 -0
  25. agent_notes/data/agents/database-specialist.md +45 -0
  26. agent_notes/data/agents/debugger.md +47 -0
  27. agent_notes/data/agents/devil.md +47 -0
  28. agent_notes/data/agents/devops.md +38 -0
  29. agent_notes/data/agents/explorer.md +23 -0
  30. agent_notes/data/agents/integrations.md +44 -0
  31. agent_notes/data/agents/lead.md +216 -0
  32. agent_notes/data/agents/performance-profiler.md +44 -0
  33. agent_notes/data/agents/refactorer.md +48 -0
  34. agent_notes/data/agents/reviewer.md +44 -0
  35. agent_notes/data/agents/security-auditor.md +44 -0
  36. agent_notes/data/agents/system-auditor.md +38 -0
  37. agent_notes/data/agents/tech-writer.md +32 -0
  38. agent_notes/data/agents/test-runner.md +36 -0
  39. agent_notes/data/agents/test-writer.md +39 -0
  40. agent_notes/data/cli/claude.yaml +25 -0
  41. agent_notes/data/cli/copilot.yaml +18 -0
  42. agent_notes/data/cli/opencode.yaml +22 -0
  43. agent_notes/data/commands/brainstorm.md +8 -0
  44. agent_notes/data/commands/debug.md +9 -0
  45. agent_notes/data/commands/review.md +10 -0
  46. agent_notes/data/global-claude.md +290 -0
  47. agent_notes/data/global-copilot.md +27 -0
  48. agent_notes/data/global-opencode.md +40 -0
  49. agent_notes/data/hooks/session-context.md.tpl +19 -0
  50. agent_notes/data/models/claude-haiku-4-5.yaml +15 -0
  51. agent_notes/data/models/claude-opus-4-1.yaml +16 -0
  52. agent_notes/data/models/claude-opus-4-5.yaml +16 -0
  53. agent_notes/data/models/claude-opus-4-6.yaml +16 -0
  54. agent_notes/data/models/claude-opus-4-7.yaml +15 -0
  55. agent_notes/data/models/claude-sonnet-4-5.yaml +16 -0
  56. agent_notes/data/models/claude-sonnet-4-6.yaml +15 -0
  57. agent_notes/data/models/claude-sonnet-4.yaml +16 -0
  58. agent_notes/data/pricing.yaml +33 -0
  59. agent_notes/data/roles/orchestrator.yaml +5 -0
  60. agent_notes/data/roles/reasoner.yaml +5 -0
  61. agent_notes/data/roles/scout.yaml +5 -0
  62. agent_notes/data/roles/worker.yaml +5 -0
  63. agent_notes/data/rules/code-quality.md +9 -0
  64. agent_notes/data/rules/safety.md +10 -0
  65. agent_notes/data/scripts/cost-report +211 -0
  66. agent_notes/data/skills/brainstorming/SKILL.md +57 -0
  67. agent_notes/data/skills/code-review/SKILL.md +64 -0
  68. agent_notes/data/skills/debugging-protocol/SKILL.md +51 -0
  69. agent_notes/data/skills/docker-compose/SKILL.md +318 -0
  70. agent_notes/data/skills/docker-compose-advanced/SKILL.md +575 -0
  71. agent_notes/data/skills/docker-dockerfile/SKILL.md +385 -0
  72. agent_notes/data/skills/docker-dockerfile-languages/SKILL.md +293 -0
  73. agent_notes/data/skills/git/SKILL.md +87 -0
  74. agent_notes/data/skills/rails-active-storage/SKILL.md +321 -0
  75. agent_notes/data/skills/rails-broadcasting/SKILL.md +374 -0
  76. agent_notes/data/skills/rails-concerns/SKILL.md +806 -0
  77. agent_notes/data/skills/rails-controllers/SKILL.md +510 -0
  78. agent_notes/data/skills/rails-controllers-advanced/SKILL.md +441 -0
  79. agent_notes/data/skills/rails-helpers/SKILL.md +677 -0
  80. agent_notes/data/skills/rails-initializers/SKILL.md +79 -0
  81. agent_notes/data/skills/rails-javascript/SKILL.md +567 -0
  82. agent_notes/data/skills/rails-jobs/SKILL.md +700 -0
  83. agent_notes/data/skills/rails-kamal/SKILL.md +483 -0
  84. agent_notes/data/skills/rails-lib/SKILL.md +101 -0
  85. agent_notes/data/skills/rails-mailers/SKILL.md +321 -0
  86. agent_notes/data/skills/rails-migrations/SKILL.md +268 -0
  87. agent_notes/data/skills/rails-models/SKILL.md +459 -0
  88. agent_notes/data/skills/rails-models-advanced/SKILL.md +398 -0
  89. agent_notes/data/skills/rails-routes/SKILL.md +804 -0
  90. agent_notes/data/skills/rails-style/SKILL.md +538 -0
  91. agent_notes/data/skills/rails-testing-controllers/SKILL.md +343 -0
  92. agent_notes/data/skills/rails-testing-models/SKILL.md +296 -0
  93. agent_notes/data/skills/rails-testing-system/SKILL.md +375 -0
  94. agent_notes/data/skills/rails-validations/SKILL.md +108 -0
  95. agent_notes/data/skills/rails-view-components/SKILL.md +511 -0
  96. agent_notes/data/skills/rails-view-components-advanced/SKILL.md +376 -0
  97. agent_notes/data/skills/rails-views/SKILL.md +413 -0
  98. agent_notes/data/skills/rails-views-advanced/SKILL.md +450 -0
  99. agent_notes/data/skills/refactoring-protocol/SKILL.md +64 -0
  100. agent_notes/data/skills/tdd/SKILL.md +57 -0
  101. agent_notes/data/templates/__init__.py +1 -0
  102. agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  103. agent_notes/data/templates/frontmatter/__init__.py +1 -0
  104. agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  105. agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  106. agent_notes/data/templates/frontmatter/__pycache__/cursor.cpython-314.pyc +0 -0
  107. agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  108. agent_notes/data/templates/frontmatter/claude.py +44 -0
  109. agent_notes/data/templates/frontmatter/opencode.py +104 -0
  110. agent_notes/doctor_checks.py +189 -0
  111. agent_notes/domain/__init__.py +17 -0
  112. agent_notes/domain/agent.py +34 -0
  113. agent_notes/domain/cli_backend.py +40 -0
  114. agent_notes/domain/diagnostics.py +29 -0
  115. agent_notes/domain/diff.py +44 -0
  116. agent_notes/domain/model.py +27 -0
  117. agent_notes/domain/role.py +13 -0
  118. agent_notes/domain/rule.py +13 -0
  119. agent_notes/domain/skill.py +15 -0
  120. agent_notes/domain/state.py +46 -0
  121. agent_notes/install_state.py +11 -0
  122. agent_notes/registries/__init__.py +16 -0
  123. agent_notes/registries/_base.py +46 -0
  124. agent_notes/registries/agent_registry.py +107 -0
  125. agent_notes/registries/cli_registry.py +89 -0
  126. agent_notes/registries/model_registry.py +85 -0
  127. agent_notes/registries/role_registry.py +64 -0
  128. agent_notes/registries/rule_registry.py +80 -0
  129. agent_notes/registries/skill_registry.py +141 -0
  130. agent_notes/services/__init__.py +8 -0
  131. agent_notes/services/diagnostics/__init__.py +47 -0
  132. agent_notes/services/diagnostics/_checks.py +272 -0
  133. agent_notes/services/diagnostics/_display.py +346 -0
  134. agent_notes/services/diagnostics/_fix.py +169 -0
  135. agent_notes/services/diff.py +349 -0
  136. agent_notes/services/fs.py +195 -0
  137. agent_notes/services/install_state_builder.py +210 -0
  138. agent_notes/services/installer.py +293 -0
  139. agent_notes/services/memory_backend.py +155 -0
  140. agent_notes/services/rendering.py +329 -0
  141. agent_notes/services/session_context.py +23 -0
  142. agent_notes/services/settings_writer.py +79 -0
  143. agent_notes/services/state_store.py +249 -0
  144. agent_notes/services/ui.py +419 -0
  145. agent_notes/services/user_config.py +62 -0
  146. agent_notes/services/validation.py +67 -0
  147. agent_notes/state.py +21 -0
  148. agent_notes-2.0.4.dist-info/METADATA +14 -0
  149. agent_notes-2.0.4.dist-info/RECORD +162 -0
  150. agent_notes-2.0.4.dist-info/WHEEL +5 -0
  151. agent_notes-2.0.4.dist-info/entry_points.txt +2 -0
  152. agent_notes-2.0.4.dist-info/licenses/LICENSE +21 -0
  153. agent_notes-2.0.4.dist-info/top_level.txt +2 -0
  154. tests/conftest.py +20 -0
  155. tests/functional/__init__.py +0 -0
  156. tests/functional/test_build_commands.py +88 -0
  157. tests/functional/test_registries.py +128 -0
  158. tests/integration/__init__.py +0 -0
  159. tests/integration/test_build_output.py +129 -0
  160. tests/plugins/__init__.py +0 -0
  161. tests/plugins/test_agents.py +93 -0
  162. tests/plugins/test_skills.py +77 -0
@@ -0,0 +1,450 @@
1
+ ---
2
+ name: rails-views-advanced
3
+ description: "Rails views advanced: Turbo Streams, JSON/Jbuilder, helpers in views, conditional rendering, and best practices"
4
+ group: rails
5
+ ---
6
+
7
+ # Views (Advanced)
8
+
9
+ ## Turbo Streams
10
+
11
+ ### Turbo Stream Template
12
+
13
+ ```erb
14
+ <%# app/views/cards/create.turbo_stream.erb %>
15
+
16
+ <%# Prepend new card to list %>
17
+ <%= turbo_stream.prepend "cards", @card %>
18
+
19
+ <%# Update form with errors or clear it %>
20
+ <% if @card.persisted? %>
21
+ <%= turbo_stream.update "new_card_form", "" %>
22
+ <% else %>
23
+ <%= turbo_stream.replace "new_card_form" do %>
24
+ <%= render "form", card: @card %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <%# Show flash message %>
29
+ <%= turbo_stream.update "flash" do %>
30
+ <div class="alert alert-success">Card created!</div>
31
+ <% end %>
32
+ ```
33
+
34
+ ### Multiple Turbo Stream Actions
35
+
36
+ ```erb
37
+ <%# app/views/cards/update.turbo_stream.erb %>
38
+
39
+ <%= turbo_stream.replace @card, @card %>
40
+
41
+ <%= turbo_stream.update "card_count" do %>
42
+ <%= pluralize(Card.count, "card") %>
43
+ <% end %>
44
+
45
+ <%= turbo_stream.append "recent_activity" do %>
46
+ <%= render "activity", card: @card, action: "updated" %>
47
+ <% end %>
48
+ ```
49
+
50
+ ### Turbo Stream Actions
51
+
52
+ ```erb
53
+ <%# Replace %>
54
+ <%= turbo_stream.replace dom_id(@card), @card %>
55
+
56
+ <%# Update (replace innerHTML) %>
57
+ <%= turbo_stream.update dom_id(@card), partial: "cards/card" %>
58
+
59
+ <%# Append %>
60
+ <%= turbo_stream.append "cards", @card %>
61
+
62
+ <%# Prepend %>
63
+ <%= turbo_stream.prepend "cards", @card %>
64
+
65
+ <%# Remove %>
66
+ <%= turbo_stream.remove @card %>
67
+
68
+ <%# Before %>
69
+ <%= turbo_stream.before dom_id(@card), partial: "cards/notice" %>
70
+
71
+ <%# After %>
72
+ <%= turbo_stream.after dom_id(@card), partial: "cards/metadata" %>
73
+ ```
74
+
75
+ ---
76
+
77
+ ## JSON Views (Jbuilder)
78
+
79
+ ### Basic JSON Template
80
+
81
+ ```ruby
82
+ # app/views/cards/show.json.jbuilder
83
+
84
+ json.id @card.id
85
+ json.title @card.title
86
+ json.description @card.description.to_plain_text
87
+ json.status @card.status
88
+ json.created_at @card.created_at
89
+ json.updated_at @card.updated_at
90
+
91
+ json.url card_url(@card)
92
+
93
+ json.creator do
94
+ json.id @card.creator.id
95
+ json.name @card.creator.name
96
+ json.email @card.creator.email
97
+ end
98
+
99
+ json.tags @card.tags, :id, :title
100
+ ```
101
+
102
+ ### JSON with Partials
103
+
104
+ ```ruby
105
+ # app/views/cards/show.json.jbuilder
106
+
107
+ json.partial! "cards/card", card: @card
108
+
109
+ json.comments @card.comments do |comment|
110
+ json.partial! "comments/comment", comment: comment
111
+ end
112
+ ```
113
+
114
+ ```ruby
115
+ # app/views/cards/_card.json.jbuilder
116
+
117
+ json.cache! card do
118
+ json.(card, :id, :number, :title, :status)
119
+ json.description card.description.to_plain_text
120
+ json.description_html card.description.to_s
121
+
122
+ json.url card_url(card)
123
+ json.created_at card.created_at.iso8601
124
+
125
+ json.creator do
126
+ json.partial! "users/user", user: card.creator
127
+ end
128
+ end
129
+ ```
130
+
131
+ ### JSON Collection
132
+
133
+ ```ruby
134
+ # app/views/cards/index.json.jbuilder
135
+
136
+ json.cards @cards do |card|
137
+ json.partial! "cards/card", card: card
138
+ end
139
+
140
+ json.meta do
141
+ json.total_count @cards.total_count
142
+ json.current_page @cards.current_page
143
+ json.total_pages @cards.total_pages
144
+ end
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Helpers in Views
150
+
151
+ ### Link Helpers
152
+
153
+ ```erb
154
+ <%= link_to "View Card", @card %>
155
+ <%= link_to "Edit", edit_card_path(@card), class: "btn" %>
156
+ <%= link_to "Delete", @card, method: :delete, data: { confirm: "Are you sure?" } %>
157
+
158
+ <%# Turbo-specific %>
159
+ <%= link_to "View", @card, data: { turbo_frame: "modal" } %>
160
+ <%= link_to "Edit", edit_card_path(@card), data: { turbo: false } %>
161
+ ```
162
+
163
+ ### Button Helpers
164
+
165
+ ```erb
166
+ <%= button_to "Delete", @card, method: :delete, class: "btn btn-danger" %>
167
+ <%= button_to "Archive", archive_card_path(@card), method: :post %>
168
+ ```
169
+
170
+ ### Image Helpers
171
+
172
+ ```erb
173
+ <%= image_tag "logo.png", alt: "Logo", class: "logo" %>
174
+ <%= image_tag card.image, size: "300x200" if card.image.attached? %>
175
+
176
+ <%# With Active Storage %>
177
+ <%= image_tag url_for(card.image) if card.image.attached? %>
178
+ <%= image_tag card.image.variant(resize_to_limit: [300, 200]) %>
179
+ ```
180
+
181
+ ### Content Tag Helpers
182
+
183
+ ```erb
184
+ <%= content_tag :div, class: "card" do %>
185
+ <h3><%= @card.title %></h3>
186
+ <% end %>
187
+
188
+ <%= tag.article class: "card", id: dom_id(@card) do %>
189
+ <h3><%= @card.title %></h3>
190
+ <% end %>
191
+
192
+ <%# Self-closing tags %>
193
+ <%= tag.br %>
194
+ <%= tag.hr %>
195
+ <%= tag.img src: "logo.png" %>
196
+ ```
197
+
198
+ ### Text Helpers
199
+
200
+ ```erb
201
+ <%= truncate(@card.description, length: 100) %>
202
+ <%= excerpt(@card.description, "keyword", radius: 50) %>
203
+ <%= highlight(@card.title, "search term") %>
204
+ <%= pluralize(@card.comments.count, "comment") %>
205
+ <%= number_to_currency(100.50) %>
206
+ <%= number_to_percentage(85.5, precision: 1) %>
207
+ <%= number_with_delimiter(1000000) %>
208
+ ```
209
+
210
+ ### Date/Time Helpers
211
+
212
+ ```erb
213
+ <%= time_ago_in_words(@card.created_at) %> ago
214
+ <%= distance_of_time_in_words(@card.created_at, Time.current) %>
215
+
216
+ <%# Formatted %>
217
+ <%= @card.created_at.strftime("%B %d, %Y") %>
218
+ <%= l(@card.created_at, format: :long) %>
219
+
220
+ <%# Time tag %>
221
+ <time datetime="<%= @card.created_at.iso8601 %>">
222
+ <%= @card.created_at.strftime("%b %d, %Y") %>
223
+ </time>
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Conditional Rendering
229
+
230
+ ### Simple Conditionals
231
+
232
+ ```erb
233
+ <% if @card.published? %>
234
+ <span class="badge badge-published">Published</span>
235
+ <% else %>
236
+ <span class="badge badge-draft">Draft</span>
237
+ <% end %>
238
+
239
+ <% unless @card.closed? %>
240
+ <%= link_to "Close", card_closure_path(@card), method: :post %>
241
+ <% end %>
242
+ ```
243
+
244
+ ### Guard Clauses
245
+
246
+ ```erb
247
+ <% if @cards.empty? %>
248
+ <p>No cards found.</p>
249
+ <% else %>
250
+ <%= render @cards %>
251
+ <% end %>
252
+
253
+ <%# With present? %>
254
+ <% if @card.description.present? %>
255
+ <div class="description">
256
+ <%= @card.description %>
257
+ </div>
258
+ <% end %>
259
+ ```
260
+
261
+ ### Ternary Operator
262
+
263
+ ```erb
264
+ <span class="status <%= @card.published? ? "active" : "inactive" %>">
265
+ <%= @card.status %>
266
+ </span>
267
+
268
+ <%= link_to(@card.closed? ? "Reopen" : "Close", card_closure_path(@card)) %>
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Iteration
274
+
275
+ ### Each Loop
276
+
277
+ ```erb
278
+ <% @cards.each do |card| %>
279
+ <%= render card %>
280
+ <% end %>
281
+
282
+ <%# With index %>
283
+ <% @cards.each_with_index do |card, index| %>
284
+ <div class="card" data-index="<%= index %>">
285
+ <%= render card %>
286
+ </div>
287
+ <% end %>
288
+ ```
289
+
290
+ ### Collection Rendering
291
+
292
+ ```erb
293
+ <%# Preferred way - cleaner %>
294
+ <%= render @cards %>
295
+
296
+ <%# Same as: %>
297
+ <% @cards.each do |card| %>
298
+ <%= render "cards/card", card: card %>
299
+ <% end %>
300
+ ```
301
+
302
+ ### Grouped Collections
303
+
304
+ ```erb
305
+ <% @cards.group_by(&:status).each do |status, cards| %>
306
+ <section class="status-group">
307
+ <h2><%= status.humanize %></h2>
308
+ <%= render cards %>
309
+ </section>
310
+ <% end %>
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Best Practices
316
+
317
+ ### DO
318
+
319
+ 1. **Keep views simple** - No business logic
320
+ ```erb
321
+ <%# Good %>
322
+ <%= render @card if @card.published? %>
323
+
324
+ <%# Bad %>
325
+ <% if @card.status == "published" && @card.visible_to?(current_user) && @card.approved? %>
326
+ <%= render @card %>
327
+ <% end %>
328
+ ```
329
+
330
+ 2. **Use explicit locals in partials**
331
+ ```erb
332
+ <%# Good %>
333
+ <%= render "card", card: @card, show_actions: true %>
334
+
335
+ <%# Bad - relies on instance variables %>
336
+ <%= render "card" %>
337
+ ```
338
+
339
+ 3. **Extract complex view logic to helpers**
340
+ ```erb
341
+ <%# Good %>
342
+ <%= card_status_badge(@card) %>
343
+
344
+ <%# Bad %>
345
+ <span class="badge badge-<%= @card.status.dasherize %> <%= 'urgent' if @card.urgent? %>">
346
+ <%= @card.status.humanize %>
347
+ </span>
348
+ ```
349
+
350
+ 4. **Use fragment caching**
351
+ ```erb
352
+ <% cache @card do %>
353
+ <%= render @card %>
354
+ <% end %>
355
+ ```
356
+
357
+ 5. **Use semantic HTML**
358
+ ```erb
359
+ <article class="card">
360
+ <header><h1><%= @card.title %></h1></header>
361
+ <section><%= @card.description %></section>
362
+ <footer><%= render "card/actions" %></footer>
363
+ </article>
364
+ ```
365
+
366
+ ### DON'T
367
+
368
+ 1. **Database queries in views**
369
+ ```erb
370
+ <%# Bad %>
371
+ <% Card.where(status: :published).each do |card| %>
372
+ <%= render card %>
373
+ <% end %>
374
+
375
+ <%# Good - query in controller %>
376
+ <%= render @published_cards %>
377
+ ```
378
+
379
+ 2. **Complex Ruby logic**
380
+ ```erb
381
+ <%# Bad %>
382
+ <% total = @cards.inject(0) { |sum, card| sum + card.value } %>
383
+
384
+ <%# Good - method in model/helper %>
385
+ <%= @cards.total_value %>
386
+ ```
387
+
388
+ 3. **Inline styles**
389
+ ```erb
390
+ <%# Bad %>
391
+ <div style="color: red; font-size: 14px;">
392
+
393
+ <%# Good %>
394
+ <div class="error-message">
395
+ ```
396
+
397
+ 4. **Raw HTML without sanitization**
398
+ ```erb
399
+ <%# Bad %>
400
+ <%= @card.description.html_safe %>
401
+
402
+ <%# Good %>
403
+ <%= sanitize @card.description %>
404
+ <%= @card.description %> <%# If it's already safe from model %>
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Testing Views
410
+
411
+ ### View Tests (Helper Tests)
412
+
413
+ ```ruby
414
+ # test/helpers/cards_helper_test.rb
415
+ class CardsHelperTest < ActionView::TestCase
416
+ test "card_status_badge returns correct badge" do
417
+ card = cards(:published)
418
+
419
+ badge = card_status_badge(card)
420
+
421
+ assert_match /badge/, badge
422
+ assert_match /published/, badge
423
+ end
424
+ end
425
+ ```
426
+
427
+ ### Testing Partials
428
+
429
+ ```ruby
430
+ # In controller tests, partials are rendered
431
+ test "index renders cards" do
432
+ get cards_path
433
+
434
+ assert_select ".card", count: Card.count
435
+ assert_select "h3", text: cards(:logo).title
436
+ end
437
+ ```
438
+
439
+ ---
440
+
441
+ ## Summary
442
+
443
+ - **Structure**: Layouts, templates, partials, shared
444
+ - **Partials**: Explicit locals, collection rendering, caching
445
+ - **Forms**: Form builders, nested forms, error handling
446
+ - **Turbo Streams**: Real-time updates without full page reload
447
+ - **JSON**: Jbuilder for API responses
448
+ - **Helpers**: Link, button, image, text, date helpers
449
+ - **Best Practices**: Keep views simple, no business logic, use helpers
450
+ - **Caching**: Fragment caching for performance
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: refactoring-protocol
3
+ description: "Safe refactoring: green tests first, one extraction at a time, structure OR behavior never both"
4
+ group: process
5
+ ---
6
+
7
+ # Refactoring Protocol
8
+
9
+ Refactoring means improving the structure of code without changing its behavior. The moment you change behavior, you are no longer refactoring — you are adding a feature or fixing a bug. These are different activities and must not be mixed.
10
+
11
+ ## Prerequisites — before you start
12
+
13
+ 1. **Tests must be green.** If the code has no tests, write characterization tests first that document what it currently does (not what it should do). Do not refactor untested code.
14
+ 2. **Understand what you're changing.** Read the code and identify exactly which smell you're addressing.
15
+ 3. **One session, one concern.** Name the refactor before starting: "extract payment logic into a service", "rename variables to match domain language", "remove duplication in validation". If you find yourself listing more than one, finish one, commit, then start the next.
16
+
17
+ ## Code smells worth addressing
18
+
19
+ - **Long method** — does more than one thing; split by responsibility.
20
+ - **Duplicated logic** — same decision made in multiple places; extract to one location.
21
+ - **Misleading names** — name describes something other than what the code does.
22
+ - **Deep nesting** — more than two levels of if/for; extract guard clauses or methods.
23
+ - **Large class** — handles multiple concerns; split by cohesion.
24
+ - **Primitive obsession** — using raw strings or ints for domain concepts; introduce a value object.
25
+ - **Feature envy** — a method that uses more of another class than its own; move it.
26
+
27
+ ## Process
28
+
29
+ ### Step 1 — Run tests (confirm green)
30
+
31
+ If any test is failing before you start: stop. Do not refactor broken code.
32
+
33
+ ### Step 2 — Make one extraction
34
+
35
+ Extract one method, rename one variable, move one class. Not all at once.
36
+
37
+ ### Step 3 — Run tests immediately
38
+
39
+ Every extraction gets a test run. If tests go red:
40
+ - Undo the extraction. Do not try to fix it forward.
41
+ - Understand why it broke before attempting again.
42
+
43
+ ### Step 4 — Commit
44
+
45
+ Each logical extraction is its own commit. This makes it reversible and reviewable independently.
46
+
47
+ ### Step 5 — Repeat
48
+
49
+ Return to Step 2 for the next extraction.
50
+
51
+ ## Hard rules
52
+
53
+ - **Structure OR behavior in one commit, never both.** If you find a bug while refactoring: stash the refactor, fix the bug in a separate commit, then resume. Mixing them makes the change impossible to review and risky to revert.
54
+ - **Do not optimize during refactor.** Performance tuning is a separate session with its own measurement baseline.
55
+ - **Do not add features during refactor.** If you notice a missing edge case: note it, address it in a separate commit after the refactor is complete.
56
+ - **Stop when the smell is gone.** Over-refactoring is as harmful as under-refactoring.
57
+
58
+ ## Done means
59
+
60
+ - Tests still green.
61
+ - One code smell addressed.
62
+ - Each logical change committed separately.
63
+ - No behavior was changed.
64
+ - No new features or bug fixes were mixed in.
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: tdd
3
+ description: "RED-GREEN-REFACTOR: write the failing test first, then make it pass, then clean up"
4
+ group: process
5
+ ---
6
+
7
+ # Test-Driven Development
8
+
9
+ ## The contract
10
+
11
+ 1. No production code before a failing test.
12
+ 2. The minimum code to pass the test — nothing more.
13
+ 3. Refactor only while tests are green.
14
+
15
+ ## RED — write a failing test
16
+
17
+ - Identify the smallest behavior to verify.
18
+ - Name the test as a specification: `test_returns_empty_list_when_no_results`, not `test_search`.
19
+ - Run it. Confirm it fails for the **right reason** — the assertion fails, not a syntax error or import problem.
20
+ - Do not write production code yet.
21
+
22
+ ## GREEN — make it pass
23
+
24
+ - Write the minimum code to pass the test. Hardcode values if that's all it takes — you'll triangulate with the next test.
25
+ - Run the test. Confirm green.
26
+ - If still failing: read the failure output carefully before changing anything else.
27
+
28
+ ## REFACTOR — clean up
29
+
30
+ - Eliminate duplication.
31
+ - Improve names.
32
+ - Extract where it improves clarity, not just to reduce line count.
33
+ - Run tests after every change. If they go red: undo the refactor, don't push through.
34
+
35
+ ## Test scope rules
36
+
37
+ - Test **behavior** from the outside, not implementation details.
38
+ - Do not test private methods directly — test through the public interface.
39
+ - Prefer fewer, meaningful assertions over many trivial ones.
40
+ - If a test requires more than three mocks to set up: it is testing too much. Split the unit.
41
+
42
+ ## When NOT to apply
43
+
44
+ - Exploratory spikes where you're learning an unfamiliar API — spike first, then write tests for what you keep.
45
+ - Tests that require so much mocking the mock becomes the thing being tested — write an integration test instead.
46
+ - Throwaway scripts with no expected lifetime.
47
+
48
+ ## Flaky tests
49
+
50
+ If a new test passes sometimes and fails other times: stop and fix it before continuing. A flaky test is worse than no test — it trains you to ignore failures.
51
+
52
+ ## Done means
53
+
54
+ - All new tests pass.
55
+ - No existing tests regressed.
56
+ - Test names describe the behavior they verify.
57
+ - No dead code or commented-out experiments remain.
@@ -0,0 +1 @@
1
+ """Templates package for agent-notes."""
@@ -0,0 +1 @@
1
+ """Frontmatter template plugins for agent-notes."""
@@ -0,0 +1,44 @@
1
+ """Claude Code frontmatter generator template."""
2
+
3
+ from typing import Dict, Any
4
+
5
+
6
+ def render(ctx: dict) -> str:
7
+ """Render YAML frontmatter for a Claude Code agent.
8
+
9
+ ctx keys:
10
+ agent_name: str
11
+ agent_config: dict (from agents.yaml entry)
12
+ model_str: str (resolved model string)
13
+ backend_name: str
14
+ backend: CLIBackend object or None
15
+ """
16
+ agent_name = ctx['agent_name']
17
+ agent_config = ctx['agent_config']
18
+ model_str = ctx['model_str']
19
+
20
+ frontmatter = ['---']
21
+ frontmatter.append(f'name: {agent_name}')
22
+ frontmatter.append(f'description: {agent_config["description"]}')
23
+ frontmatter.append(f'model: {model_str}')
24
+
25
+ # Add Claude-specific settings
26
+ claude_config = agent_config.get('claude', {})
27
+ if 'tools' in claude_config:
28
+ frontmatter.append(f'tools: {claude_config["tools"]}')
29
+ if 'disallowedTools' in claude_config:
30
+ frontmatter.append(f'disallowedTools: {claude_config["disallowedTools"]}')
31
+ if 'memory' in claude_config:
32
+ frontmatter.append(f'memory: {claude_config["memory"]}')
33
+
34
+ # Add metadata
35
+ frontmatter.append(f'color: {agent_config["color"]}')
36
+ frontmatter.append(f'effort: {agent_config["effort"]}')
37
+ frontmatter.append('---')
38
+
39
+ return '\n'.join(frontmatter)
40
+
41
+
42
+ def post_process(prompt: str, ctx: dict) -> str:
43
+ """Optional: transform the prompt body. Return as-is by default."""
44
+ return prompt