agent-notes 2.25.0__tar.gz → 2.27.0__tar.gz

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 (272) hide show
  1. {agent_notes-2.25.0 → agent_notes-2.27.0}/PKG-INFO +1 -1
  2. agent_notes-2.27.0/agent_notes/VERSION +1 -0
  3. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/doctor.py +41 -0
  4. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/notes.py +4 -2
  5. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/cost_reporting.md +5 -1
  6. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/execution.md +1 -1
  7. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/guardrails.md +2 -4
  8. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/hard_limits.md +1 -2
  9. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/pricing.yaml +3 -3
  10. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/code-review/SKILL.md +4 -2
  11. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/improve-codebase-architecture/SKILL.md +1 -1
  12. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/migrate-memory/SKILL.md +1 -1
  13. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md +1 -1
  14. agent_notes-2.27.0/agent_notes/data/skills/rsi/SKILL.md +60 -0
  15. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/skill_registry.py +2 -1
  16. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_claude_backend.py +10 -62
  17. agent_notes-2.27.0/agent_notes/scripts/_formatting.py +120 -0
  18. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_opencode_backend.py +10 -68
  19. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/rendering.py +2 -1
  20. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/PKG-INFO +1 -1
  21. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/SOURCES.txt +3 -0
  22. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_doctor_command.py +162 -0
  23. agent_notes-2.27.0/tests/functional/memory/test_memory_add_local_backend.py +55 -0
  24. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/test_skills.py +15 -0
  25. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/registries/test_registries.py +30 -0
  26. agent_notes-2.27.0/tests/unit/scripts/test_opencode_backend_pricing.py +100 -0
  27. agent_notes-2.27.0/tests/unit/services/test_rendering_includes.py +212 -0
  28. agent_notes-2.25.0/agent_notes/VERSION +0 -1
  29. agent_notes-2.25.0/agent_notes/scripts/_formatting.py +0 -49
  30. agent_notes-2.25.0/tests/unit/services/test_rendering_includes.py +0 -88
  31. {agent_notes-2.25.0 → agent_notes-2.27.0}/LICENSE +0 -0
  32. {agent_notes-2.25.0 → agent_notes-2.27.0}/README.md +0 -0
  33. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/__init__.py +0 -0
  34. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/__main__.py +0 -0
  35. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/cli.py +0 -0
  36. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/__init__.py +0 -0
  37. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/_install_helpers.py +0 -0
  38. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/build.py +0 -0
  39. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/config.py +0 -0
  40. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/hook.py +0 -0
  41. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/info.py +0 -0
  42. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/install.py +0 -0
  43. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/list.py +0 -0
  44. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/__init__.py +0 -0
  45. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/_common.py +0 -0
  46. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/migrate.py +0 -0
  47. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/reset.py +0 -0
  48. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/transfer.py +0 -0
  49. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/vault.py +0 -0
  50. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/wiki.py +0 -0
  51. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/regenerate.py +0 -0
  52. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/set_role.py +0 -0
  53. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/uninstall.py +0 -0
  54. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/validate.py +0 -0
  55. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/__init__.py +0 -0
  56. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/_common.py +0 -0
  57. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/cost_report.py +0 -0
  58. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/execute.py +0 -0
  59. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/orchestrator.py +0 -0
  60. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/config.py +0 -0
  61. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/constants.py +0 -0
  62. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/agents.yaml +0 -0
  63. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/analyst.md +0 -0
  64. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/api-reviewer.md +0 -0
  65. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/architect.md +0 -0
  66. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/coder.md +0 -0
  67. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/database-specialist.md +0 -0
  68. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/debugger.md +0 -0
  69. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/devil.md +0 -0
  70. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/devops.md +0 -0
  71. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/explorer.md +0 -0
  72. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/integrations.md +0 -0
  73. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/lead.md +0 -0
  74. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/performance-profiler.md +0 -0
  75. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/refactorer.md +0 -0
  76. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/reviewer.md +0 -0
  77. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/security-auditor.md +0 -0
  78. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/phase0.md +0 -0
  79. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/pipelines.md +0 -0
  80. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/review.md +0 -0
  81. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/verification.md +0 -0
  82. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/wiki_compile.md +0 -0
  83. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/system-auditor.md +0 -0
  84. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/tech-writer.md +0 -0
  85. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-runner.md +0 -0
  86. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-writer.md +0 -0
  87. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/wiki-compiler.md +0 -0
  88. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/claude.yaml +0 -0
  89. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/copilot.yaml +0 -0
  90. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/opencode.yaml +0 -0
  91. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/brainstorm.md +0 -0
  92. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/debug.md +0 -0
  93. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/review.md +0 -0
  94. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-claude.md +0 -0
  95. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-copilot.md +0 -0
  96. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-opencode.md +0 -0
  97. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/hooks/session-context.md.tpl +0 -0
  98. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-haiku-4-5.yaml +0 -0
  99. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-1.yaml +0 -0
  100. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-5.yaml +0 -0
  101. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-6.yaml +0 -0
  102. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-7.yaml +0 -0
  103. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-8.yaml +0 -0
  104. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-5.yaml +0 -0
  105. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-6.yaml +0 -0
  106. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4.yaml +0 -0
  107. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/claude.yaml +0 -0
  108. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode-index.js.template +0 -0
  109. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode.yaml +0 -0
  110. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/orchestrator.yaml +0 -0
  111. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/reasoner.yaml +0 -0
  112. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/scout.yaml +0 -0
  113. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/worker.yaml +0 -0
  114. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/rules/code-quality.md +0 -0
  115. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/rules/safety.md +0 -0
  116. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/brainstorming/SKILL.md +0 -0
  117. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/caveman/SKILL.md +0 -0
  118. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/debugging-protocol/SKILL.md +0 -0
  119. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/SKILL.md +0 -0
  120. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/compose.md +0 -0
  121. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/dockerfile.md +0 -0
  122. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/git/SKILL.md +0 -0
  123. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-me/SKILL.md +0 -0
  124. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-with-docs/SKILL.md +0 -0
  125. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/handoff/SKILL.md +0 -0
  126. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/ingest/SKILL.md +0 -0
  127. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/obsidian-memory/SKILL.md +0 -0
  128. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/LOGIC.md +0 -0
  129. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/SKILL.md +0 -0
  130. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/UI.md +0 -0
  131. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/SKILL.md +0 -0
  132. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/controllers.md +0 -0
  133. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/frontend.md +0 -0
  134. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/infra.md +0 -0
  135. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/models.md +0 -0
  136. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/testing.md +0 -0
  137. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/views.md +0 -0
  138. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/setup-project-context/SKILL.md +0 -0
  139. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/tdd/SKILL.md +0 -0
  140. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-issues/SKILL.md +0 -0
  141. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-prd/SKILL.md +0 -0
  142. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/write-a-skill/SKILL.md +0 -0
  143. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/zoom-out/SKILL.md +0 -0
  144. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/__init__.py +0 -0
  145. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  146. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__init__.py +0 -0
  147. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  148. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  149. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  150. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/claude.py +0 -0
  151. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/opencode.py +0 -0
  152. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/doctor_checks.py +0 -0
  153. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/__init__.py +0 -0
  154. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/agent.py +0 -0
  155. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/cli_backend.py +0 -0
  156. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/diagnostics.py +0 -0
  157. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/diff.py +0 -0
  158. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/model.py +0 -0
  159. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/role.py +0 -0
  160. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/rule.py +0 -0
  161. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/skill.py +0 -0
  162. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/state.py +0 -0
  163. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/__init__.py +0 -0
  164. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/_base.py +0 -0
  165. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/agent_registry.py +0 -0
  166. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/cli_registry.py +0 -0
  167. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/model_registry.py +0 -0
  168. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/role_registry.py +0 -0
  169. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/rule_registry.py +0 -0
  170. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/__init__.py +0 -0
  171. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_pricing.py +0 -0
  172. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/cost_report.py +0 -0
  173. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/__init__.py +0 -0
  174. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/_memory_utils.py +0 -0
  175. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/counts.py +0 -0
  176. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/credentials.py +0 -0
  177. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/__init__.py +0 -0
  178. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_checks.py +0 -0
  179. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_display.py +0 -0
  180. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_fix.py +0 -0
  181. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diff.py +0 -0
  182. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/fs.py +0 -0
  183. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/install_state_builder.py +0 -0
  184. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/installer.py +0 -0
  185. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/local_backend.py +0 -0
  186. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/memory_router.py +0 -0
  187. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/migrations/__init__.py +0 -0
  188. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/obsidian_backend.py +0 -0
  189. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/session_context.py +0 -0
  190. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/settings_writer.py +0 -0
  191. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/state_store.py +0 -0
  192. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/ui.py +0 -0
  193. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/user_config.py +0 -0
  194. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/validation.py +0 -0
  195. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/__init__.py +0 -0
  196. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/_wiki_utils.py +0 -0
  197. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_index.py +0 -0
  198. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_ingest.py +0 -0
  199. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_lint.py +0 -0
  200. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_query.py +0 -0
  201. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_storage.py +0 -0
  202. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki_backend.py +0 -0
  203. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/dependency_links.txt +0 -0
  204. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/entry_points.txt +0 -0
  205. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/requires.txt +0 -0
  206. {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/top_level.txt +0 -0
  207. {agent_notes-2.25.0 → agent_notes-2.27.0}/pyproject.toml +0 -0
  208. {agent_notes-2.25.0 → agent_notes-2.27.0}/setup.cfg +0 -0
  209. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/conftest.py +0 -0
  210. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/__init__.py +0 -0
  211. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/__init__.py +0 -0
  212. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_config_command.py +0 -0
  213. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_info_command.py +0 -0
  214. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_install_command.py +0 -0
  215. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_list_command.py +0 -0
  216. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_regenerate_command.py +0 -0
  217. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_uninstall_command.py +0 -0
  218. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_validate_command.py +0 -0
  219. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/memory/__init__.py +0 -0
  220. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/memory/test_memory_command.py +0 -0
  221. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/scripts/__init__.py +0 -0
  222. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/scripts/test_release_script.py +0 -0
  223. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/__init__.py +0 -0
  224. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/build_output/__init__.py +0 -0
  225. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/build_output/test_build_output.py +0 -0
  226. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/install/__init__.py +0 -0
  227. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/install/test_install_methods.py +0 -0
  228. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/__init__.py +0 -0
  229. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/test_plugin_builders.py +0 -0
  230. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/__init__.py +0 -0
  231. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/claude/__init__.py +0 -0
  232. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/claude/test_agents.py +0 -0
  233. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/__init__.py +0 -0
  234. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/__init__.py +0 -0
  235. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_cost_report_subcommand.py +0 -0
  236. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_count_agents.py +0 -0
  237. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_info.py +0 -0
  238. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_add_description.py +0 -0
  239. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_imports.py +0 -0
  240. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_migrate.py +0 -0
  241. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_imports.py +0 -0
  242. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_orchestrator_skip.py +0 -0
  243. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_preflight.py +0 -0
  244. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_steps.py +0 -0
  245. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/wizard/test_cost_report_step.py +0 -0
  246. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/registries/__init__.py +0 -0
  247. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/__init__.py +0 -0
  248. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report.py +0 -0
  249. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report_scoping.py +0 -0
  250. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_formatting_tty.py +0 -0
  251. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_time_aggregation.py +0 -0
  252. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/__init__.py +0 -0
  253. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_build_functions.py +0 -0
  254. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_credential_filter.py +0 -0
  255. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_credentials.py +0 -0
  256. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_fs.py +0 -0
  257. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_hooks.py +0 -0
  258. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_plan.py +0 -0
  259. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_local_backend.py +0 -0
  260. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend.py +0 -0
  261. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend_io.py +0 -0
  262. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_router.py +0 -0
  263. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_session_context.py +0 -0
  264. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_settings_writer.py +0 -0
  265. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_skill_filtering.py +0 -0
  266. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_state_store.py +0 -0
  267. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_user_config_cost_report.py +0 -0
  268. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_validation.py +0 -0
  269. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_backend.py +0 -0
  270. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_imports.py +0 -0
  271. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/test_import_health.py +0 -0
  272. {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/test_memory_dir_for_backend.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-notes
3
- Version: 2.25.0
3
+ Version: 2.27.0
4
4
  Summary: AI agent configuration manager for Claude Code, OpenCode, and Copilot
5
5
  Author-email: Eugene Naumov <min.verkligheten@gmail.com>
6
6
  License-Expression: MIT
@@ -0,0 +1 @@
1
+ 2.27.0
@@ -2,6 +2,8 @@
2
2
 
3
3
  from pathlib import Path
4
4
 
5
+ from ..registries.skill_registry import load_skill_registry
6
+
5
7
  # Re-export for backward compatibility. New code should import from agent_notes.domain.
6
8
  from ..domain.diagnostics import Issue, FixAction # noqa: F401
7
9
 
@@ -42,6 +44,42 @@ from ..services.fs import (
42
44
  files_differ
43
45
  )
44
46
 
47
+ # Canonical group vocabulary for skill frontmatter.
48
+ # "process" and "domain" come from the base skills in data/skills/.
49
+ # "rails", "docker", and "kamal" come from the sub-skills that are generated
50
+ # during the release/packaging step and land in data/skills/ of the built
51
+ # package (e.g. rails-models → group: rails, rails-kamal → group: kamal,
52
+ # docker-compose → group: docker). There is no single source-of-truth
53
+ # constant elsewhere in the codebase, so the full vocabulary is listed here.
54
+ _VALID_GROUPS = {"process", "domain", "rails", "docker", "kamal"}
55
+ _VALID_MEMORY_BACKENDS = {"obsidian", "wiki", "local", "none"}
56
+
57
+
58
+ def check_skill_frontmatter(scope: str, issues: list, fix_actions: list, profile_label: str = "") -> None:
59
+ """Warn (non-fatal) about skill frontmatter violations.
60
+
61
+ Checks every skill for:
62
+ - non-empty name and description
63
+ - group, if present, is in {"process", "domain"}
64
+ - requires_memory tokens, if present, are each in {"obsidian", "wiki", "local", "none"}
65
+
66
+ Violations are printed as advisories and do NOT affect issues/fix_actions or exit code.
67
+ """
68
+ registry = load_skill_registry()
69
+ for skill in registry.all():
70
+ if not skill.name:
71
+ print(f" [skill-frontmatter] {skill.path.name}: 'name' is empty")
72
+ if not skill.description:
73
+ print(f" [skill-frontmatter] {skill.path.name}: 'description' is empty")
74
+ if skill.group and skill.group not in _VALID_GROUPS:
75
+ print(f" [skill-frontmatter] {skill.name}: 'group' value '{skill.group}' is not in {sorted(_VALID_GROUPS)}")
76
+ if skill.requires_memory:
77
+ for token in skill.requires_memory.split(","):
78
+ token = token.strip()
79
+ if token and token not in _VALID_MEMORY_BACKENDS:
80
+ print(f" [skill-frontmatter] {skill.name}: 'requires_memory' token '{token}' is not in {sorted(_VALID_MEMORY_BACKENDS)}")
81
+
82
+
45
83
  def _check_session_hook(scope: str, issues: list) -> None:
46
84
  """Check that the Claude Code SessionStart hook is registered in settings.json."""
47
85
  from ..services.settings_writer import has_hook
@@ -162,6 +200,9 @@ def diagnose(scope: str, fix: bool = False) -> bool:
162
200
  # SessionStart hook check (Claude Code only)
163
201
  _check_session_hook(scope, issues)
164
202
 
203
+ # Skill frontmatter advisory check (warn-only, non-fatal)
204
+ check_skill_frontmatter(scope, issues, fix_actions)
205
+
165
206
  # Print role→model assignments
166
207
  state = load_current_state()
167
208
  if state is not None:
@@ -45,8 +45,10 @@ def do_add(title: str, body: str, note_type: str = "context", agent: str = "", p
45
45
  )
46
46
  print(f"{Color.GREEN}Note saved: {note_path}{Color.NC}")
47
47
  else:
48
- print("The `add` subcommand is for obsidian or wiki storage.")
49
- print("For local storage, write files directly to the agent subdirectory.")
48
+ import sys
49
+ print("The `add` subcommand is for obsidian or wiki storage.", file=sys.stderr)
50
+ print("For local storage, write files directly to the agent subdirectory.", file=sys.stderr)
51
+ sys.exit(1)
50
52
 
51
53
 
52
54
  def do_list() -> None:
@@ -4,10 +4,14 @@ At the END of every response, run `agent-notes cost-report` and include the outp
4
4
 
5
5
  **Session cost** (cumulative for the entire conversation):
6
6
 
7
- Render every column the `agent-notes cost-report` CLI emits — `agent(model)`, `in/out/cache`, `time`, `actual`, `vs Claude Opus 4.7` — in that order. Do not split, drop, or rename columns. Preserve the data verbatim.
7
+ Render every column the `agent-notes cost-report` CLI emits — `agent(model)`, `in/out/cache`, `time`, `actual`, `vs Claude Opus 4.8` — in that order. Do not split, drop, or rename columns. Preserve the data verbatim.
8
8
 
9
9
  **On failure or skip — never fabricate.** If `agent-notes cost-report` returns non-zero, errors, or you skip running it, do NOT render a placeholder table or invent rows like `(cost report unavailable — agent-notes cost-report not run)`. Instead, print one plain line under the heading:
10
10
 
11
11
  `Cost report skipped: <one-line reason>`
12
12
 
13
13
  If the command ran but produced an error message, print the error verbatim under the heading instead of a table. Fabricating a table when the CLI did not run is a violation.
14
+
15
+ Cost table: once at end of response, never mid-response.
16
+
17
+ Always include the cost report at the end of every response.
@@ -86,7 +86,7 @@ Never spawn one agent per bullet point from the user's prompt. Combine related s
86
86
 
87
87
  Skip agents for: simple questions (answer directly), single-file edits (coder alone), or two-grep lookups (do it yourself).
88
88
 
89
- Give each agent a specific task with all context (paths, criteria). Always include the cost report at the end of every response.
89
+ Give each agent a specific task with all context (paths, criteria).
90
90
 
91
91
  ### Permission pre-check (HARD RULE)
92
92
 
@@ -9,10 +9,8 @@
9
9
  7. "Let me just verify this one thing" followed by 10 reads → if verification needs 10 reads, dispatch.
10
10
  8. Breaking tasks into steps so small they have no independent value → group into meaningful chunks.
11
11
  9. Writing a plan that only restates the user's words → a plan must include discovery findings, dependency order, and flagged risks.
12
- 10. Skipping the cost report at the end of a response always include it.
13
- 11. Fabricating a cost-report table or placeholder rows when `agent-notes cost-report` did not run successfully forbidden. Print "Cost report skipped: <reason>" on a single line instead.
14
- 12. Reporting "done" before tests pass and plan items match → forbidden by Done Gate.
15
- 13. Reporting "done" / "complete" / "shipped" without an `agent-notes memory add ... session lead` call covering this work → forbidden by the Done Gate.
12
+ 10. Reporting "done" before tests pass and plan items matchforbidden by Done Gate.
13
+ 11. Reporting "done" / "complete" / "shipped" without an `agent-notes memory add ... session lead` call covering this work forbidden by the Done Gate.
16
14
 
17
15
  ## Done Gate (HARD RULE)
18
16
 
@@ -13,7 +13,7 @@ You MUST NOT directly:
13
13
  - Run installs, builds, migrations, or destructive commands — dispatch `devops`
14
14
  - Use `bash` for anything beyond the read-only verification list above
15
15
 
16
- If you feel the urge to "just quickly check a file" — STOP. Dispatch `explorer`. Every file read by the lead is a budget leak (Opus tokens are 30× Haiku).
16
+ If you feel the urge to "just quickly check a file" — STOP. Dispatch `explorer`. Every file read by the lead is a budget leak (Opus tokens are 5× Haiku).
17
17
 
18
18
  Exception: trivial requests (factual questions, conversational replies, single-line answers) may be handled inline with no tools.
19
19
 
@@ -25,4 +25,3 @@ Exception: trivial requests (factual questions, conversational replies, single-l
25
25
  - Plans: structured bullet lists with file paths. No prose paragraphs.
26
26
  - Agent briefings: context + task + acceptance criteria. No commentary or justification.
27
27
  - Never narrate internal deliberation — report outcomes only.
28
- - Cost table: once at end of response, never mid-response.
@@ -1,5 +1,5 @@
1
1
  baseline:
2
- label: Claude Opus 4.7
2
+ label: Claude Opus 4.8
3
3
  price:
4
4
  in: 5.00
5
5
  out: 25.00
@@ -16,8 +16,8 @@ providers:
16
16
  match: "*sonnet*"
17
17
  price: {in: 3.00, out: 15.00, cache: 0.30}
18
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*"]
19
+ - name: Claude Opus 4.8 / 4.7 / 4.6 / 4.5
20
+ match: ["*opus-4.8*", "*opus-4.7*", "*opus-4.6*", "*opus-4.5*"]
21
21
  price: {in: 5.00, out: 25.00, cache: 0.50}
22
22
  updated_at: "2026-04"
23
23
  - name: Claude Opus (legacy)
@@ -47,14 +47,16 @@ Work through these five lenses in order. Report findings grouped by lens, ranked
47
47
 
48
48
  ## Output format
49
49
 
50
+ Emit each finding as a record: `severity` (blocking | suggestion) · `file` · `line` · `finding` · `why` · `fix` (if applicable). When the output is consumed by another agent, emit JSON objects with exactly those keys. For a human summary, group by severity:
51
+
50
52
  ```
51
53
  BLOCKING
52
- - [file:line] [finding] — [why it matters]
54
+ - [file:line] [finding] — [why it matters] → [fix]
53
55
 
54
56
  SUGGESTIONS
55
57
  - [file:line] [finding] — [alternative if applicable]
56
58
 
57
- APPROVED (if no blocking issues)
59
+ APPROVED (state explicitly when there are no blocking findings)
58
60
  ```
59
61
 
60
62
  A BLOCKING finding must be resolved before merge. A SUGGESTION is optional.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: improve-codebase-architecture
3
- description: "Find deepening opportunities — modules where the interface is nearly as complex as the implementation. Use when user wants to improve architecture, reduce coupling, make code more testable, or says 'clean up the design'."
3
+ description: "Find deepening opportunities — modules where the interface is nearly as complex as the implementation. Use when user wants to improve architecture, reduce coupling, make code more testable, or says 'clean up the design'. For broad code-quality hardening use rsi; for a single safe refactor use refactoring-protocol."
4
4
  group: process
5
5
  ---
6
6
 
@@ -2,7 +2,7 @@
2
2
  name: migrate-memory
3
3
  description: "Reconcile the Obsidian vault or Wiki knowledge base to the latest canonical format. Use after upgrading agent-notes or when vault structure looks outdated or inconsistent."
4
4
  group: process
5
- requires_memory: obsidian, wiki
5
+ requires_memory: obsidian,wiki
6
6
  ---
7
7
 
8
8
  # Migrate Memory
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: refactoring-protocol
3
- description: "Safe refactoring: green tests first, one extraction at a time, structure OR behavior never both. Use when user wants to refactor code, reduce duplication, or says 'clean this up'."
3
+ description: "Safe refactoring: green tests first, one extraction at a time, structure OR behavior never both. Use when user wants to refactor code, reduce duplication, or says 'clean this up'. For an iterative multi-dimensional cleanup loop use rsi; for module or interface redesign use improve-codebase-architecture."
4
4
  group: process
5
5
  ---
6
6
 
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: rsi
3
+ description: "Recursive code-improvement loop: iteratively harden an existing codebase across bugs, performance, quality, consistency/homogeneity, pattern adherence, tests, atomicity, independence, and DRY — strictly without adding functionality. Use when the user wants to improve, clean up, or harden existing code, says 'rsi', or asks to raise code quality without new features. For a single one-shot refactor use refactoring-protocol; for module or interface redesign use improve-codebase-architecture."
4
+ group: process
5
+ argument-hint: "[path or scope, optional]"
6
+ ---
7
+
8
+ # RSI — Recursive Self-Improvement (Code)
9
+
10
+ Iteratively improve EXISTING code until it stops yielding improvements. The lead orchestrates; specialized agents do the work. This is a quality loop, not a feature loop.
11
+
12
+ ## Prime invariant
13
+
14
+ - **Behavior-preserving.** NEVER add functionality, new features, new public API, or new config. Only improve what already exists.
15
+ - **Tests green before a pass and after every change.** If the target has no test coverage, write a characterization test FIRST, then improve.
16
+ - **One change = one concern.** Structure OR behavior, never both in the same change.
17
+
18
+ ## The loop (lead-orchestrated, loop-until-dry)
19
+
20
+ 1. **Scope.** Resolve the target (arg path, or whole project). Identify the test command and confirm the suite is green. If it is red, stop and report — fix the suite before improving.
21
+ 2. **Scan — one dimension at a time.** Dispatch read-only agents to produce a ranked list of concrete opportunities:
22
+ - `debugger` / `security-auditor` → bugs, correctness, vulnerabilities
23
+ - `performance-profiler` → hot paths, N+1, redundant work
24
+ - `system-auditor` → duplication, dead code, coupling, inconsistent implementations of one concept
25
+ - `reviewer` → readability, naming, pattern & consistency adherence
26
+ - `test-writer` (read-only pass) → coverage gaps
27
+
28
+ Each opportunity is a **finding record**: `file` · `line` · `dimension` · `severity` (blocker | major | minor) · `why` · `fix` (one-line proposed change). When a downstream agent consumes the scan, emit findings as JSON objects with exactly those keys; otherwise the dashed form `file:line — dimension/severity — why — fix` is fine.
29
+
30
+ 3. **Prioritize.** Order: correctness/safety > missing tests on touched code > DRY/duplication > consistency/homogeneity > pattern & convention fit > performance > clarity/naming. Drop anything that changes behavior or adds capability.
31
+ 4. **Apply ONE atomic, independent change.** Dispatch `coder` (bugfix) or `refactorer` (behavior-preserving cleanup). Smallest viable diff.
32
+ 5. **Verify.** Run affected tests — must stay green. `reviewer` confirms: no behavior change, fits conventions, genuinely improves the dimension. On regression → revert and re-plan.
33
+ 6. **Commit (auto, atomic).** One concern per commit, independent and revertable. Use the `git` skill's message format. Then take the next opportunity.
34
+ 7. **Repeat passes.** Converge when TWO consecutive full passes surface no new actionable improvement. Then report.
35
+
36
+ ## Dimensions rubric
37
+
38
+ Each dimension: what to **hunt**, what to **fix**, what to **leave alone**.
39
+
40
+ - **Bugs & correctness** — off-by-one, nil/None, races, missing error handling, unhandled edge cases. Fix minimally + add a regression test. Don't redesign.
41
+ - **Performance** — measured hot paths, N+1 queries, redundant work, bad complexity, unbounded growth. Don't micro-optimize cold paths or trade clarity for guesswork.
42
+ - **Code quality** — long methods, deep nesting, unclear names, magic values. Extract, apply guard clauses, rename. Don't gold-plate.
43
+ - **Consistency / homogeneity** — the same kind of thing implemented multiple different ways: mixed styles for one object type, divergent shapes for one concept, inconsistent signatures or return types. Converge on one canonical form and reduce needless variation. Distinct from DRY — this targets divergent *expression* of one concept, not duplicated *logic*. Don't force genuinely different things into a false-common shape.
44
+ - **Pattern adherence** — match the project's dominant idioms, structure, and conventions. Align outliers. Don't invent new patterns.
45
+ - **Tests** — cover changed or risky code, fix flaky/slow tests, add missing edge cases. Don't test trivial getters.
46
+ - **Atomicity** — split god-functions and god-classes into single-responsibility units. Don't over-fragment.
47
+ - **Independence** — reduce coupling, remove hidden global state, narrow interfaces. Don't add abstraction layers nobody needs.
48
+ - **DRY** — collapse genuine duplication into one source of truth. Don't DRY accidental similarity (premature abstraction is worse than duplication).
49
+ - **Dead code** — unused functions, variables, imports, branches. Delete after confirming no external use.
50
+
51
+ ## Gates (hard)
52
+
53
+ - **Green-before / green-after.** A red suite halts the loop.
54
+ - **No-feature gate.** If a change adds capability, it is out of scope — reject it.
55
+ - **Atomic & independent commits.** Revert on regression with `git revert` — never `reset --hard` or force-push.
56
+ - **Max 2 review rounds per change,** then accept or drop it.
57
+
58
+ ## Done
59
+
60
+ Report: improvements grouped by dimension, commits made, tests added, deferrals (with reasons), and anything skipped as out-of-scope (new functionality).
@@ -86,7 +86,8 @@ def _parse_skill_frontmatter(skill_md_path: Path) -> tuple[str, Optional[str], O
86
86
  elif key == 'description':
87
87
  description = value
88
88
  elif key == 'requires_memory':
89
- requires_memory = value
89
+ tokens = [t.strip() for t in value.split(",")]
90
+ requires_memory = ",".join(t for t in tokens if t)
90
91
 
91
92
  # If no description in frontmatter, use first non-empty line after frontmatter
92
93
  if not description:
@@ -6,8 +6,7 @@ from pathlib import Path
6
6
 
7
7
  from . import _pricing
8
8
  from ._formatting import (
9
- BOLD, DIM, GREEN, YELLOW, NC,
10
- tier_color, fmt_tokens, fmt_cost, fmt_time,
9
+ fmt_time, render_cost_table,
11
10
  )
12
11
  from ..services.state_store import state_file as _state_file, load_state as _load_state
13
12
 
@@ -279,66 +278,15 @@ def run(since: float | None = None, session_id: str | None = None) -> int:
279
278
  ms = agent_time_ms.get(label, 0)
280
279
  return fmt_time(ms / 1000) if ms > 0 else "n/a"
281
280
 
282
- agent_col_w = max(len(f"{a}({m})") for a, m, *_ in costs) + 2
283
- tok_col_w = max(
284
- max(len(fmt_tokens(i, o, c)) for _, _, i, o, c, *_ in costs),
285
- len(fmt_tokens(
286
- sum(i for _, _, i, *_ in costs),
287
- sum(o for _, _, _, o, *_ in costs),
288
- sum(c for _, _, _, _, c, *_ in costs),
289
- ))
290
- ) + 2
291
- all_time_strs = [_time_str_for(a) for a, *_ in costs]
292
- time_col_w = max(len(s) for s in all_time_strs) + 2
293
- W = (agent_col_w, tok_col_w, time_col_w, 12, 12)
294
-
295
- bl_label = _pricing.baseline_label()
296
- header = (
297
- f"{'agent(model)':<{W[0]}}"
298
- f" {'in/out/cache':<{W[1]}}"
299
- f" {'time':<{W[2]}}"
300
- f" {'actual':<{W[3]}}"
301
- f" {f'vs {bl_label}':<{W[4]}}"
281
+ total_time_ms = sum(
282
+ lead_time_ms if agent == "lead" else agent_time_ms.get(agent, 0)
283
+ for agent, *_ in costs
302
284
  )
303
- print(BOLD + header + NC)
304
- print(DIM + "-" * len(header) + NC)
305
-
306
- total_inp = total_outp = total_cache = 0
307
- total_actual = total_vs = 0.0
308
- total_time_ms = 0
309
-
310
- for agent, model, inp, outp, cache, actual, vs in costs:
311
- label = f"{agent}({model})"
312
- col = tier_color(model)
313
- t_str = _time_str_for(agent)
314
- print(
315
- col + f"{label:<{W[0]}}" + NC
316
- + f" {fmt_tokens(inp, outp, cache):<{W[1]}}"
317
- + f" {t_str:<{W[2]}}"
318
- + f" {fmt_cost(actual):<{W[3]}}"
319
- + f" {fmt_cost(vs):<{W[4]}}"
320
- )
321
- total_inp += inp
322
- total_outp += outp
323
- total_cache += cache
324
- total_actual += actual
325
- total_vs += vs
326
- if agent == "lead":
327
- total_time_ms += lead_time_ms
328
- else:
329
- total_time_ms += agent_time_ms.get(agent, 0)
330
-
331
- saved_pct = round((1 - total_actual / total_vs) * 100) if total_vs else 0
332
- total_label = f"TOTAL (saved {saved_pct}%)"
333
285
  total_time_str = fmt_time(total_time_ms / 1000) if total_time_ms > 0 else "n/a"
334
- col = GREEN if total_actual <= 5 else YELLOW
335
- print(
336
- col + BOLD
337
- + f"{total_label:<{W[0]}}"
338
- + f" {fmt_tokens(total_inp, total_outp, total_cache):<{W[1]}}"
339
- + f" {total_time_str:<{W[2]}}"
340
- + f" {fmt_cost(total_actual):<{W[3]}}"
341
- + f" {fmt_cost(total_vs):<{W[4]}}"
342
- + NC
343
- )
286
+
287
+ rows = [
288
+ (f"{agent}({model})", model, inp, outp, cache, _time_str_for(agent), actual, vs)
289
+ for agent, model, inp, outp, cache, actual, vs in costs
290
+ ]
291
+ render_cost_table(rows, total_time_str, _pricing.baseline_label())
344
292
  return 0
@@ -0,0 +1,120 @@
1
+ """ANSI color constants and shared formatting helpers."""
2
+ import os
3
+ import sys
4
+
5
+ _USE_COLOR = sys.stdout.isatty() and not os.environ.get("NO_COLOR")
6
+
7
+ BOLD = "\033[1m" if _USE_COLOR else ""
8
+ DIM = "\033[2m" if _USE_COLOR else ""
9
+ YELLOW = "\033[0;33m" if _USE_COLOR else ""
10
+ GREEN = "\033[0;32m" if _USE_COLOR else ""
11
+ CYAN = "\033[0;36m" if _USE_COLOR else ""
12
+ NC = "\033[0m" if _USE_COLOR else ""
13
+
14
+
15
+ def tier_color(model_id: str) -> str:
16
+ if not _USE_COLOR:
17
+ return ""
18
+ if "opus" in model_id:
19
+ return YELLOW
20
+ if "sonnet" in model_id:
21
+ return CYAN
22
+ return DIM
23
+
24
+
25
+ def fmt_num(n: int) -> str:
26
+ if n >= 1_000_000:
27
+ return f"{n / 1_000_000:.2f}m"
28
+ if n >= 1_000:
29
+ return f"{n / 1_000:.2f}k"
30
+ return str(n)
31
+
32
+
33
+ def fmt_tokens(inp, outp, cache) -> str:
34
+ return f"{fmt_num(inp)}/{fmt_num(outp)}/{fmt_num(cache)}"
35
+
36
+
37
+ def fmt_time(sec: float) -> str:
38
+ s = int(round(sec))
39
+ if s < 60:
40
+ return f"{s}s"
41
+ m, s = divmod(s, 60)
42
+ if m < 60:
43
+ return f"{m}m {s}s" if s else f"{m}m"
44
+ h, m = divmod(m, 60)
45
+ return f"{h}h {m}m" if m else f"{h}h"
46
+
47
+
48
+ def fmt_cost(c: float) -> str:
49
+ return f"${c:.4f}"
50
+
51
+
52
+ def render_cost_table(
53
+ rows: list[tuple],
54
+ total_time_str: str,
55
+ baseline_label: str,
56
+ ) -> None:
57
+ """Print a cost table to stdout.
58
+
59
+ Each row must be a tuple of:
60
+ (label: str, model: str, inp: int, outp: int, cache: int,
61
+ time_str: str, actual: float, vs: float)
62
+
63
+ total_time_str — pre-formatted total time (backends compute it differently)
64
+ baseline_label — label for the rightmost "vs" column header
65
+ """
66
+ agent_col_w = max(len(label) for label, *_ in rows) + 2
67
+ tok_col_w = max(
68
+ max(len(fmt_tokens(i, o, c)) for _, _, i, o, c, *_ in rows),
69
+ len(fmt_tokens(
70
+ sum(i for _, _, i, *_ in rows),
71
+ sum(o for _, _, _, o, *_ in rows),
72
+ sum(c for _, _, _, _, c, *_ in rows),
73
+ ))
74
+ ) + 2
75
+ time_col_w = max(
76
+ max(len(t) for _, _, _, _, _, t, *_ in rows),
77
+ len(total_time_str)
78
+ ) + 2
79
+ W = (agent_col_w, tok_col_w, time_col_w, 12, 12)
80
+
81
+ header = (
82
+ f"{'agent(model)':<{W[0]}}"
83
+ f" {'in/out/cache':<{W[1]}}"
84
+ f" {'time':<{W[2]}}"
85
+ f" {'actual':<{W[3]}}"
86
+ f" {f'vs {baseline_label}':<{W[4]}}"
87
+ )
88
+ print(BOLD + header + NC)
89
+ print(DIM + "-" * len(header) + NC)
90
+
91
+ total_inp = total_outp = total_cache = 0
92
+ total_actual = total_vs = 0.0
93
+
94
+ for label, model, inp, outp, cache, time_str, actual, vs in rows:
95
+ col = tier_color(model)
96
+ print(
97
+ col + f"{label:<{W[0]}}" + NC
98
+ + f" {fmt_tokens(inp, outp, cache):<{W[1]}}"
99
+ + f" {time_str:<{W[2]}}"
100
+ + f" {fmt_cost(actual):<{W[3]}}"
101
+ + f" {fmt_cost(vs):<{W[4]}}"
102
+ )
103
+ total_inp += inp
104
+ total_outp += outp
105
+ total_cache += cache
106
+ total_actual += actual
107
+ total_vs += vs
108
+
109
+ saved_pct = round((1 - total_actual / total_vs) * 100) if total_vs else 0
110
+ total_label = f"TOTAL (saved {saved_pct}%)"
111
+ col = GREEN if total_actual <= 5 else YELLOW
112
+ print(
113
+ col + BOLD
114
+ + f"{total_label:<{W[0]}}"
115
+ + f" {fmt_tokens(total_inp, total_outp, total_cache):<{W[1]}}"
116
+ + f" {total_time_str:<{W[2]}}"
117
+ + f" {fmt_cost(total_actual):<{W[3]}}"
118
+ + f" {fmt_cost(total_vs):<{W[4]}}"
119
+ + NC
120
+ )
@@ -3,10 +3,7 @@ import sqlite3
3
3
  from pathlib import Path
4
4
 
5
5
  from . import _pricing
6
- from ._formatting import (
7
- BOLD, DIM, GREEN, YELLOW, NC,
8
- tier_color, fmt_tokens, fmt_time, fmt_cost,
9
- )
6
+ from ._formatting import fmt_time, render_cost_table
10
7
 
11
8
  DB = Path.home() / ".local/share/opencode/opencode.db"
12
9
 
@@ -63,7 +60,7 @@ def run() -> int:
63
60
  return 0
64
61
 
65
62
  records = [
66
- (agent, model or "unknown", inp or 0, outp or 0, cache or 0, sec or 0)
63
+ (agent, _pricing.normalize_model(model or "unknown"), inp or 0, outp or 0, cache or 0, sec or 0)
67
64
  for agent, model, inp, outp, cache, sec in rows
68
65
  ]
69
66
 
@@ -74,68 +71,13 @@ def run() -> int:
74
71
  for agent, model, inp, outp, cache, sec in records
75
72
  ]
76
73
 
77
- _total_inp = sum(i for _, _, i, *_ in costs)
78
- _total_outp = sum(o for _, _, _, o, *_ in costs)
79
- _total_cache = sum(c for _, _, _, _, c, *_ in costs)
80
- _max_sec = max(s for _, _, _, _, _, s, *_ in costs)
81
- _total_sec = sum(s for _, _, _, _, _, s, *_ in costs)
82
- _total_time = f"{fmt_time(_max_sec)} / {fmt_time(_total_sec)} seq"
83
-
84
- agent_col_w = max(len(f"{a}({m})") for a, m, *_ in costs) + 2
85
- tok_col_w = max(
86
- max(len(fmt_tokens(i, o, c)) for _, _, i, o, c, *_ in costs),
87
- len(fmt_tokens(_total_inp, _total_outp, _total_cache))
88
- ) + 2
89
- time_col_w = max(
90
- max(len(fmt_time(s)) for _, _, _, _, _, s, *_ in costs),
91
- len(_total_time)
92
- ) + 2
93
- W = (agent_col_w, tok_col_w, time_col_w, 12, 12)
94
-
95
- bl_label = _pricing.baseline_label()
96
- header = (
97
- f"{'agent(model)':<{W[0]}}"
98
- f" {'in/out/cache':<{W[1]}}"
99
- f" {'time':<{W[2]}}"
100
- f" {'actual':<{W[3]}}"
101
- f" {f'vs {bl_label}':<{W[4]}}"
102
- )
103
- print(BOLD + header + NC)
104
- print(DIM + "-" * len(header) + NC)
74
+ max_sec = max(s for _, _, _, _, _, s, *_ in costs)
75
+ total_sec = sum(s for _, _, _, _, _, s, *_ in costs)
76
+ total_time_str = f"{fmt_time(max_sec)} / {fmt_time(total_sec)} seq"
105
77
 
106
- total_inp = total_outp = total_cache = 0
107
- total_actual = total_vs = max_sec = total_sec = 0.0
108
-
109
- for agent, model, inp, outp, cache, sec, actual, vs in costs:
110
- label = f"{agent}({model})"
111
- time_str = fmt_time(sec)
112
- col = tier_color(model)
113
- print(
114
- col + f"{label:<{W[0]}}" + NC
115
- + f" {fmt_tokens(inp, outp, cache):<{W[1]}}"
116
- + f" {time_str:<{W[2]}}"
117
- + f" {fmt_cost(actual):<{W[3]}}"
118
- + f" {fmt_cost(vs):<{W[4]}}"
119
- )
120
- total_inp += inp
121
- total_outp += outp
122
- total_cache += cache
123
- total_actual += actual
124
- total_vs += vs
125
- max_sec = max(max_sec, sec)
126
- total_sec += sec
127
-
128
- saved_pct = round((1 - total_actual / total_vs) * 100) if total_vs else 0
129
- total_label = f"TOTAL (saved {saved_pct}%)"
130
- total_time = _total_time
131
- col = GREEN if total_actual <= 5 else YELLOW
132
- print(
133
- col + BOLD
134
- + f"{total_label:<{W[0]}}"
135
- + f" {fmt_tokens(total_inp, total_outp, total_cache):<{W[1]}}"
136
- + f" {total_time:<{W[2]}}"
137
- + f" {fmt_cost(total_actual):<{W[3]}}"
138
- + f" {fmt_cost(total_vs):<{W[4]}}"
139
- + NC
140
- )
78
+ rows = [
79
+ (f"{agent}({model})", model, inp, outp, cache, fmt_time(sec), actual, vs)
80
+ for agent, model, inp, outp, cache, sec, actual, vs in costs
81
+ ]
82
+ render_cost_table(rows, total_time_str, _pricing.baseline_label())
141
83
  return 0
@@ -139,7 +139,8 @@ def generate_agent_files(agents_config: Dict[str, Any], tiers: Dict[str, Any],
139
139
 
140
140
  # Expand shared-content include directives (<!-- include: NAME -->)
141
141
  # No-op if shared/ directory is absent.
142
- prompt_content = expand_includes(prompt_content, AGENTS_DIR / "shared")
142
+ _agent_include_skip = set() if user_config.get("cost_report_enabled", False) else {"cost_reporting"}
143
+ prompt_content = expand_includes(prompt_content, AGENTS_DIR / "shared", skip=_agent_include_skip)
143
144
 
144
145
  # Substitute {{MEMORY_PATH}} with the configured vault/memory path.
145
146
  _st = _load_state_fn()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-notes
3
- Version: 2.25.0
3
+ Version: 2.27.0
4
4
  Summary: AI agent configuration manager for Claude Code, OpenCode, and Copilot
5
5
  Author-email: Eugene Naumov <min.verkligheten@gmail.com>
6
6
  License-Expression: MIT
@@ -125,6 +125,7 @@ agent_notes/data/skills/rails/models.md
125
125
  agent_notes/data/skills/rails/testing.md
126
126
  agent_notes/data/skills/rails/views.md
127
127
  agent_notes/data/skills/refactoring-protocol/SKILL.md
128
+ agent_notes/data/skills/rsi/SKILL.md
128
129
  agent_notes/data/skills/setup-project-context/SKILL.md
129
130
  agent_notes/data/skills/tdd/SKILL.md
130
131
  agent_notes/data/skills/to-issues/SKILL.md
@@ -206,6 +207,7 @@ tests/functional/commands/test_regenerate_command.py
206
207
  tests/functional/commands/test_uninstall_command.py
207
208
  tests/functional/commands/test_validate_command.py
208
209
  tests/functional/memory/__init__.py
210
+ tests/functional/memory/test_memory_add_local_backend.py
209
211
  tests/functional/memory/test_memory_command.py
210
212
  tests/functional/scripts/__init__.py
211
213
  tests/functional/scripts/test_release_script.py
@@ -241,6 +243,7 @@ tests/unit/scripts/__init__.py
241
243
  tests/unit/scripts/test_cost_report.py
242
244
  tests/unit/scripts/test_cost_report_scoping.py
243
245
  tests/unit/scripts/test_formatting_tty.py
246
+ tests/unit/scripts/test_opencode_backend_pricing.py
244
247
  tests/unit/scripts/test_time_aggregation.py
245
248
  tests/unit/services/__init__.py
246
249
  tests/unit/services/test_build_functions.py