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,16 @@
1
+ id: claude-opus-4-5
2
+ label: Claude Opus 4.5
3
+ family: claude
4
+ class: opus
5
+ deprecated: true
6
+ aliases:
7
+ anthropic: claude-opus-4-5
8
+ github-copilot: github-copilot/claude-opus-4.5
9
+ pricing:
10
+ input: 5.00
11
+ output: 25.00
12
+ cache: 0.50
13
+ capabilities:
14
+ vision: true
15
+ long_context: false
16
+ tool_use: true
@@ -0,0 +1,16 @@
1
+ id: claude-opus-4-6
2
+ label: Claude Opus 4.6
3
+ family: claude
4
+ class: opus
5
+ deprecated: true
6
+ aliases:
7
+ anthropic: claude-opus-4-6
8
+ github-copilot: github-copilot/claude-opus-4.6
9
+ pricing:
10
+ input: 5.00
11
+ output: 25.00
12
+ cache: 0.50
13
+ capabilities:
14
+ vision: true
15
+ long_context: true
16
+ tool_use: true
@@ -0,0 +1,15 @@
1
+ id: claude-opus-4-7
2
+ label: Claude Opus 4.7
3
+ family: claude
4
+ class: opus
5
+ aliases:
6
+ anthropic: opus
7
+ github-copilot: github-copilot/claude-opus-4.7
8
+ pricing:
9
+ input: 5.00
10
+ output: 25.00
11
+ cache: 0.50
12
+ capabilities:
13
+ vision: true
14
+ long_context: true
15
+ tool_use: true
@@ -0,0 +1,16 @@
1
+ id: claude-sonnet-4-5
2
+ label: Claude Sonnet 4.5
3
+ family: claude
4
+ class: sonnet
5
+ deprecated: true
6
+ aliases:
7
+ anthropic: claude-sonnet-4-5
8
+ github-copilot: github-copilot/claude-sonnet-4.5
9
+ pricing:
10
+ input: 3.00
11
+ output: 15.00
12
+ cache: 0.30
13
+ capabilities:
14
+ vision: true
15
+ long_context: false
16
+ tool_use: true
@@ -0,0 +1,15 @@
1
+ id: claude-sonnet-4-6
2
+ label: Claude Sonnet 4.6
3
+ family: claude
4
+ class: sonnet
5
+ aliases:
6
+ anthropic: sonnet
7
+ github-copilot: github-copilot/claude-sonnet-4.6
8
+ pricing:
9
+ input: 3.00
10
+ output: 15.00
11
+ cache: 0.30
12
+ capabilities:
13
+ vision: true
14
+ long_context: true
15
+ tool_use: true
@@ -0,0 +1,16 @@
1
+ id: claude-sonnet-4
2
+ label: Claude Sonnet 4
3
+ family: claude
4
+ class: sonnet
5
+ deprecated: true
6
+ aliases:
7
+ anthropic: claude-sonnet-4-20250514
8
+ github-copilot: github-copilot/claude-sonnet-4
9
+ pricing:
10
+ input: 3.00
11
+ output: 15.00
12
+ cache: 0.30
13
+ capabilities:
14
+ vision: true
15
+ long_context: true
16
+ tool_use: true
@@ -0,0 +1,33 @@
1
+ baseline:
2
+ label: Claude Opus 4.7
3
+ price:
4
+ in: 5.00
5
+ out: 25.00
6
+ cache: 0.50
7
+
8
+ providers:
9
+ - name: Anthropic
10
+ models:
11
+ - name: Claude Haiku 4.5
12
+ match: "*haiku*"
13
+ price: {in: 1.00, out: 5.00, cache: 0.10}
14
+ updated_at: "2026-04"
15
+ - name: Claude Sonnet
16
+ match: "*sonnet*"
17
+ price: {in: 3.00, out: 15.00, cache: 0.30}
18
+ updated_at: "2026-04"
19
+ - name: Claude Opus 4.7 / 4.6 / 4.5
20
+ match: ["*opus-4.7*", "*opus-4.6*", "*opus-4.5*"]
21
+ price: {in: 5.00, out: 25.00, cache: 0.50}
22
+ updated_at: "2026-04"
23
+ - name: Claude Opus (legacy)
24
+ match: ["*opus-4.1*", "*opus*"]
25
+ price: {in: 15.00, out: 75.00, cache: 1.50}
26
+ updated_at: "2026-04"
27
+
28
+ - name: OpenAI
29
+ models:
30
+ - name: GPT-4 / o-series
31
+ match: ["gpt-*", "o1*", "o3*", "o4*"]
32
+ price: {in: 2.50, out: 10.00, cache: 0.50}
33
+ updated_at: "2026-04"
@@ -0,0 +1,5 @@
1
+ name: orchestrator
2
+ label: Orchestrator
3
+ description: Plans and delegates complex multi-step tasks. Low volume, high reasoning needed.
4
+ typical_class: opus
5
+ color: purple
@@ -0,0 +1,5 @@
1
+ name: reasoner
2
+ label: Reasoner
3
+ description: Deep debugging and architecture analysis. Low volume, max reasoning needed.
4
+ typical_class: opus
5
+ color: red
@@ -0,0 +1,5 @@
1
+ name: scout
2
+ label: Scout
3
+ description: Fast file discovery, pattern search. High volume, low reasoning.
4
+ typical_class: haiku
5
+ color: cyan
@@ -0,0 +1,5 @@
1
+ name: worker
2
+ label: Worker
3
+ description: Implements code, writes tests, does focused analysis. Medium volume.
4
+ typical_class: sonnet
5
+ color: green
@@ -0,0 +1,9 @@
1
+ # Code Quality
2
+
3
+ - Read existing code first. Match project indentation, naming, and file organization.
4
+ - Small focused methods. One responsibility per method.
5
+ - Guard clauses and early returns over deep nesting.
6
+ - Meaningful names that describe purpose, not implementation.
7
+ - Only build what was asked for. No speculative abstractions.
8
+ - Validate at system boundaries (user input, external APIs). Trust internal code.
9
+ - No comments for obvious code. Comment the "why", not the "what".
@@ -0,0 +1,10 @@
1
+ # Safety
2
+
3
+ - Confirm before destructive or irreversible operations:
4
+ - `git push --force`, `git reset --hard`, amending published commits
5
+ - `rm -rf`, deleting files or branches, dropping database tables
6
+ - Operations visible to others: pushing code, commenting on PRs/issues
7
+ - Never commit secrets: `.env`, `*.pem`, credentials, API keys, tokens.
8
+ - Never bypass safety checks (`--no-verify`, `--force`) without explicit user request.
9
+ - Never force-push to main or master branches.
10
+ - When encountering obstacles, do not use destructive actions as shortcuts.
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env python3
2
+ """Session cost report — prices sourced from agent_notes/data/pricing.yaml."""
3
+ import sqlite3
4
+ from fnmatch import fnmatch
5
+ from pathlib import Path
6
+
7
+ BOLD = "\033[1m"
8
+ DIM = "\033[2m"
9
+ YELLOW = "\033[0;33m"
10
+ GREEN = "\033[0;32m"
11
+ CYAN = "\033[0;36m"
12
+ NC = "\033[0m"
13
+
14
+ PRICING = {{PRICING}}
15
+
16
+ DB = Path.home() / ".local/share/opencode/opencode.db"
17
+
18
+ SQL = """
19
+ WITH cs AS (SELECT id FROM session WHERE parent_id IS NULL ORDER BY time_created DESC LIMIT 1),
20
+ conv_start AS (
21
+ SELECT COALESCE(
22
+ (SELECT json_extract(m2.data,'$.time.created')
23
+ FROM message m1 JOIN message m2 ON m1.session_id=m2.session_id
24
+ WHERE m1.session_id=(SELECT id FROM cs)
25
+ AND json_extract(m2.data,'$.time.created') > json_extract(m1.data,'$.time.created')
26
+ AND json_extract(m2.data,'$.time.created') - json_extract(m1.data,'$.time.created') > 1800000
27
+ AND NOT EXISTS (
28
+ SELECT 1 FROM message mx WHERE mx.session_id=m1.session_id
29
+ AND json_extract(mx.data,'$.time.created') > json_extract(m1.data,'$.time.created')
30
+ AND json_extract(mx.data,'$.time.created') < json_extract(m2.data,'$.time.created'))
31
+ ORDER BY json_extract(m1.data,'$.time.created') DESC LIMIT 1),
32
+ 0) AS start_ts
33
+ )
34
+ SELECT
35
+ COALESCE(json_extract(m.data,'$.agent'), 'lead') AS agent,
36
+ (SELECT json_extract(m2.data,'$.modelID') FROM message m2
37
+ WHERE m2.session_id = s.id AND json_extract(m2.data,'$.role') = 'assistant'
38
+ ORDER BY json_extract(m2.data,'$.time.completed') DESC LIMIT 1) AS model,
39
+ SUM(json_extract(m.data,'$.tokens.input')) AS inp,
40
+ SUM(json_extract(m.data,'$.tokens.output')) AS outp,
41
+ SUM(json_extract(m.data,'$.tokens.cache.read')) AS cache,
42
+ ROUND(SUM(
43
+ CASE WHEN json_extract(m.data,'$.time.completed') IS NOT NULL
44
+ AND json_extract(m.data,'$.time.created') IS NOT NULL
45
+ THEN (json_extract(m.data,'$.time.completed') - json_extract(m.data,'$.time.created')) / 1000.0
46
+ ELSE 0 END
47
+ ), 1) AS sec
48
+ FROM session s
49
+ JOIN message m ON m.session_id = s.id
50
+ CROSS JOIN cs
51
+ CROSS JOIN conv_start
52
+ WHERE (s.parent_id = cs.id OR s.id = cs.id)
53
+ AND json_extract(m.data,'$.role') = 'assistant'
54
+ AND json_extract(m.data,'$.time.created') >= conv_start.start_ts
55
+ AND (s.time_created >= conv_start.start_ts OR s.id = (SELECT id FROM cs))
56
+ GROUP BY s.id
57
+ """
58
+
59
+
60
+ def _build_price_table() -> list[tuple[list[str], dict]]:
61
+ rows = []
62
+ for provider in PRICING.get("providers", []):
63
+ for model in provider.get("models", []):
64
+ patterns = model["match"] if isinstance(model["match"], list) else [model["match"]]
65
+ rows.append((patterns, model["price"]))
66
+ return rows
67
+
68
+
69
+ _PRICE_TABLE = _build_price_table()
70
+ _BASELINE = PRICING["baseline"]["price"]
71
+ _BASELINE_LABEL = PRICING["baseline"]["label"]
72
+
73
+
74
+ def get_price(model_id: str) -> dict:
75
+ for patterns, price in _PRICE_TABLE:
76
+ if any(fnmatch(model_id, p) for p in patterns):
77
+ return price
78
+ return {"in": 3.00, "out": 15.00, "cache": 0.30}
79
+
80
+
81
+ def calculate_cost(model_id: str, inp: int, outp: int, cache: int) -> float:
82
+ p = get_price(model_id)
83
+ return (inp * p["in"] + outp * p["out"] + cache * p["cache"]) / 1_000_000
84
+
85
+
86
+ def baseline_cost(inp: int, outp: int, cache: int) -> float:
87
+ p = _BASELINE
88
+ return (inp * p["in"] + outp * p["out"] + cache * p["cache"]) / 1_000_000
89
+
90
+
91
+ def tier_color(model_id: str) -> str:
92
+ if "opus" in model_id:
93
+ return YELLOW
94
+ if "sonnet" in model_id:
95
+ return CYAN
96
+ return DIM
97
+
98
+
99
+ def fmt_num(n: int) -> str:
100
+ if n >= 1_000_000:
101
+ return f"{n / 1_000_000:.2f}m"
102
+ if n >= 1_000:
103
+ return f"{n / 1_000:.2f}k"
104
+ return str(n)
105
+
106
+
107
+ def fmt_tokens(inp, outp, cache) -> str:
108
+ return f"{fmt_num(inp)}/{fmt_num(outp)}/{fmt_num(cache)}"
109
+
110
+
111
+ def fmt_time(sec: float) -> str:
112
+ s = int(round(sec))
113
+ if s < 60:
114
+ return f"{s}s"
115
+ m, s = divmod(s, 60)
116
+ if m < 60:
117
+ return f"{m}m {s}s" if s else f"{m}m"
118
+ h, m = divmod(m, 60)
119
+ return f"{h}h {m}m" if m else f"{h}h"
120
+
121
+
122
+ def fmt_cost(c: float) -> str:
123
+ return f"${c:.4f}"
124
+
125
+
126
+ def main() -> None:
127
+ if not DB.exists():
128
+ print(f"Database not found: {DB}")
129
+ return
130
+
131
+ rows = sqlite3.connect(DB).execute(SQL).fetchall()
132
+ if not rows:
133
+ print("No sessions found.")
134
+ return
135
+
136
+ records = [
137
+ (agent, model or "unknown", inp or 0, outp or 0, cache or 0, sec or 0)
138
+ for agent, model, inp, outp, cache, sec in rows
139
+ ]
140
+
141
+ costs = [
142
+ (agent, model, inp, outp, cache, sec,
143
+ calculate_cost(model, inp, outp, cache),
144
+ baseline_cost(inp, outp, cache))
145
+ for agent, model, inp, outp, cache, sec in records
146
+ ]
147
+
148
+ _total_inp = sum(i for _, _, i, *_ in costs)
149
+ _total_outp = sum(o for _, _, _, o, *_ in costs)
150
+ _total_cache= sum(c for _, _, _, _, c, *_ in costs)
151
+ _max_sec = max(s for _, _, _, _, _, s, *_ in costs)
152
+ _total_sec = sum(s for _, _, _, _, _, s, *_ in costs)
153
+ _total_time = f"{fmt_time(_max_sec)} / {fmt_time(_total_sec)} seq"
154
+
155
+ agent_col_w = max(len(f"{a}({m})") for a, m, *_ in costs) + 2
156
+ tok_col_w = max(
157
+ max(len(fmt_tokens(i, o, c)) for _, _, i, o, c, *_ in costs),
158
+ len(fmt_tokens(_total_inp, _total_outp, _total_cache))
159
+ ) + 2
160
+ time_col_w = max(
161
+ max(len(fmt_time(s)) for _, _, _, _, _, s, *_ in costs),
162
+ len(_total_time)
163
+ ) + 2
164
+ W = (agent_col_w, tok_col_w, time_col_w, 12, 12)
165
+
166
+ header = (
167
+ f"{'agent(model)':<{W[0]}}"
168
+ f" {'in/out/cache':<{W[1]}}"
169
+ f" {'time':<{W[2]}}"
170
+ f" {'actual':<{W[3]}}"
171
+ f" {f'vs {_BASELINE_LABEL}':<{W[4]}}"
172
+ )
173
+ print(BOLD + header + NC)
174
+ print(DIM + "-" * len(header) + NC)
175
+
176
+ total_inp = total_outp = total_cache = 0
177
+ total_actual = total_vs = max_sec = total_sec = 0.0
178
+
179
+ for agent, model, inp, outp, cache, sec, actual, vs in costs:
180
+ label = f"{agent}({model})"
181
+ time_str = fmt_time(sec)
182
+ col = tier_color(model)
183
+ print(
184
+ col + f"{label:<{W[0]}}" + NC
185
+ + f" {fmt_tokens(inp, outp, cache):<{W[1]}}"
186
+ + f" {time_str:<{W[2]}}"
187
+ + f" {fmt_cost(actual):<{W[3]}}"
188
+ + f" {fmt_cost(vs):<{W[4]}}"
189
+ )
190
+ total_inp += inp; total_outp += outp; total_cache += cache
191
+ total_actual += actual; total_vs += vs
192
+ max_sec = max(max_sec, sec)
193
+ total_sec += sec
194
+
195
+ saved_pct = round((1 - total_actual / total_vs) * 100) if total_vs else 0
196
+ total_label = f"TOTAL (saved {saved_pct}%)"
197
+ total_time = _total_time
198
+ col = GREEN if total_actual <= 5 else YELLOW
199
+ print(
200
+ col + BOLD
201
+ + f"{total_label:<{W[0]}}"
202
+ + f" {fmt_tokens(total_inp, total_outp, total_cache):<{W[1]}}"
203
+ + f" {total_time:<{W[2]}}"
204
+ + f" {fmt_cost(total_actual):<{W[3]}}"
205
+ + f" {fmt_cost(total_vs):<{W[4]}}"
206
+ + NC
207
+ )
208
+
209
+
210
+ if __name__ == "__main__":
211
+ main()
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: brainstorming
3
+ description: "Explore multiple approaches before committing — read context, surface tradeoffs, then decide"
4
+ group: process
5
+ ---
6
+
7
+ # Brainstorming
8
+
9
+ Use when the problem has multiple valid solutions and the choice has long-term consequences: API design, data model, architecture, technology selection.
10
+
11
+ ## Process
12
+
13
+ ### 1. Read the context first
14
+
15
+ Before generating options, read:
16
+ - Existing patterns in the codebase — there may already be an established approach to follow.
17
+ - Similar features already implemented — don't invent something the codebase already knows how to do.
18
+ - Any stated constraints in tickets, comments, or configuration.
19
+
20
+ ### 2. Generate options (diverge)
21
+
22
+ Produce at least three meaningfully distinct approaches. For each:
23
+ - **Name** — one noun phrase.
24
+ - **Summary** — two sentences max.
25
+ - **Main advantage** — what it does best.
26
+ - **Main cost or risk** — what you're giving up.
27
+
28
+ Do not evaluate yet. Generate first. If one option is clearly dominant, still generate alternatives — the exercise surfaces the tradeoffs you'd otherwise miss.
29
+
30
+ If a key technical assumption is unproven, include a **spike option**: a throwaway implementation to test the risky assumption before committing to a direction.
31
+
32
+ ### 3. Apply constraints (filter)
33
+
34
+ Filter against the project's real constraints:
35
+ - Performance requirements
36
+ - Team familiarity and maintainability
37
+ - Existing patterns and dependencies in the codebase
38
+ - Timeline and scope
39
+
40
+ Remove options that violate hard constraints. Do not remove options just because they're unfamiliar or non-obvious.
41
+
42
+ ### 4. Recommend (converge)
43
+
44
+ Pick one option. State:
45
+ - Which option you recommend.
46
+ - Why it wins against the specific alternatives — not in the abstract.
47
+ - What you are explicitly trading away — be honest, not diplomatic.
48
+
49
+ Present the recommendation. Do not begin implementation until the user agrees.
50
+
51
+ ## Anti-patterns
52
+
53
+ - Generating one real option and two obvious strawmen to make it look like a comparison.
54
+ - Recommending the first option you thought of.
55
+ - Listing tradeoffs without actually comparing them against each other.
56
+ - Skipping the codebase read and inventing patterns from scratch.
57
+ - Framing a spike as a commitment — spikes are exploratory, not production code.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: code-review
3
+ description: "Systematic code review: correctness, safety, performance, clarity, consistency"
4
+ group: process
5
+ ---
6
+
7
+ # Code Review
8
+
9
+ Work through these five lenses in order. Report findings grouped by lens, ranked by severity within each group.
10
+
11
+ ## Lens 1 — Correctness
12
+
13
+ - Does the logic match the stated intent?
14
+ - Are edge cases handled: empty input, nil/None, off-by-one, concurrent access, zero/negative values?
15
+ - Are error paths handled and surfaced to callers correctly?
16
+ - Do the tests cover behavior, not just the happy path?
17
+ - Is there new code with no tests at all? That is a blocking issue.
18
+
19
+ ## Lens 2 — Safety
20
+
21
+ - Is user input validated at the system boundary?
22
+ - Are secrets, credentials, or PII handled safely — not logged, not exposed in responses?
23
+ - Are SQL queries parameterized, not interpolated?
24
+ - Are file paths sanitized before use?
25
+ - Does this change affect authentication or authorization logic? If yes, flag for deeper scrutiny.
26
+
27
+ ## Lens 3 — Performance
28
+
29
+ - Are there N+1 queries — loading a record, then querying for each related record in a loop?
30
+ - Are expensive operations (network calls, disk I/O, serialization) inside hot loops?
31
+ - Are large collections being loaded into memory when streaming or pagination would suffice?
32
+ - Is the change reversible if it causes a production performance regression?
33
+
34
+ ## Lens 4 — Clarity
35
+
36
+ - Are names accurate — do they describe what, not how?
37
+ - Is control flow easy to follow? Guard clauses beat deep nesting.
38
+ - Are comments present only where the why is non-obvious? No comments that restate what the code already says.
39
+ - Would a new team member understand this without asking?
40
+
41
+ ## Lens 5 — Consistency
42
+
43
+ - Does this match the existing patterns in the codebase?
44
+ - Does it follow project naming conventions?
45
+ - Does it introduce a new abstraction or dependency that already exists elsewhere?
46
+ - Are the tests written in the same style as existing tests?
47
+
48
+ ## Output format
49
+
50
+ ```
51
+ BLOCKING
52
+ - [file:line] [finding] — [why it matters]
53
+
54
+ SUGGESTIONS
55
+ - [file:line] [finding] — [alternative if applicable]
56
+
57
+ APPROVED (if no blocking issues)
58
+ ```
59
+
60
+ A BLOCKING finding must be resolved before merge. A SUGGESTION is optional.
61
+
62
+ ## Scope discipline
63
+
64
+ Do not flag cosmetic changes unless they create real ambiguity. A review that lists 20 nits trains authors to ignore reviews entirely.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: debugging-protocol
3
+ description: "4-phase systematic debugging: instrument → evidence → hypothesis → fix"
4
+ group: process
5
+ ---
6
+
7
+ # Debugging Protocol
8
+
9
+ Never guess. Never change code randomly. Follow the four phases.
10
+
11
+ ## Phase 1 — Instrument
12
+
13
+ Before forming any hypothesis, add observability:
14
+ - Add logging at the entry and exit of the failing code path.
15
+ - Log inputs, intermediate values, and outputs — not just that something happened.
16
+ - If a test is failing: read the **full stack trace** before doing anything else.
17
+ - If a runtime error: reproduce in the smallest possible isolated case.
18
+
19
+ Do not modify production logic in this phase.
20
+
21
+ **For regressions:** run `git log --oneline -20` and use `git bisect` to find the commit that introduced the failure before instrumenting. Knowing when it broke tells you where to look.
22
+
23
+ ## Phase 2 — Gather evidence
24
+
25
+ Run the instrumented version. Collect:
26
+ - Exact error message and file:line location.
27
+ - What values are actually present vs. what was expected.
28
+ - The full call stack at the point of failure.
29
+ - Whether this is a **code bug** or a **test bug** — read the test's intent before assuming the production code is wrong.
30
+
31
+ Check dependency changelogs if a third-party library was recently updated and the failure is at an integration boundary.
32
+
33
+ ## Phase 3 — Form a hypothesis
34
+
35
+ State it explicitly before touching anything:
36
+
37
+ > "I believe the bug is caused by X, because the evidence shows Y."
38
+
39
+ Test with the smallest possible change — one that confirms or disproves the hypothesis without being the permanent fix. If the hypothesis is wrong: return to Phase 2 with the new evidence. Do not stack changes.
40
+
41
+ ## Phase 4 — Fix
42
+
43
+ Apply the minimal fix for the root cause:
44
+ - Fix the root cause, not the symptom.
45
+ - Remove all instrumentation from Phase 1.
46
+ - Run the full test suite.
47
+ - Confirm the original failure is gone and nothing else regressed.
48
+
49
+ ## Escalation rule
50
+
51
+ Three failed hypothesis cycles means stop and do an architectural review. The bug likely signals that a design assumption is wrong, not just a logic error in one function.