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.
- {agent_notes-2.25.0 → agent_notes-2.27.0}/PKG-INFO +1 -1
- agent_notes-2.27.0/agent_notes/VERSION +1 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/doctor.py +41 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/notes.py +4 -2
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/cost_reporting.md +5 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/execution.md +1 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/guardrails.md +2 -4
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/hard_limits.md +1 -2
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/pricing.yaml +3 -3
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/code-review/SKILL.md +4 -2
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/improve-codebase-architecture/SKILL.md +1 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/migrate-memory/SKILL.md +1 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md +1 -1
- agent_notes-2.27.0/agent_notes/data/skills/rsi/SKILL.md +60 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/skill_registry.py +2 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_claude_backend.py +10 -62
- agent_notes-2.27.0/agent_notes/scripts/_formatting.py +120 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_opencode_backend.py +10 -68
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/rendering.py +2 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/PKG-INFO +1 -1
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/SOURCES.txt +3 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_doctor_command.py +162 -0
- agent_notes-2.27.0/tests/functional/memory/test_memory_add_local_backend.py +55 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/test_skills.py +15 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/registries/test_registries.py +30 -0
- agent_notes-2.27.0/tests/unit/scripts/test_opencode_backend_pricing.py +100 -0
- agent_notes-2.27.0/tests/unit/services/test_rendering_includes.py +212 -0
- agent_notes-2.25.0/agent_notes/VERSION +0 -1
- agent_notes-2.25.0/agent_notes/scripts/_formatting.py +0 -49
- agent_notes-2.25.0/tests/unit/services/test_rendering_includes.py +0 -88
- {agent_notes-2.25.0 → agent_notes-2.27.0}/LICENSE +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/README.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/__main__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/cli.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/_install_helpers.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/build.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/config.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/hook.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/info.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/install.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/list.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/_common.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/migrate.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/reset.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/transfer.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/vault.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/memory/wiki.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/regenerate.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/set_role.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/uninstall.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/validate.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/_common.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/cost_report.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/execute.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/orchestrator.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/config.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/constants.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/agents.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/analyst.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/api-reviewer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/architect.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/coder.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/database-specialist.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/debugger.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/devil.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/devops.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/explorer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/integrations.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/lead.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/performance-profiler.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/refactorer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/reviewer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/security-auditor.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/phase0.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/pipelines.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/review.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/verification.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/wiki_compile.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/system-auditor.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/tech-writer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-runner.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-writer.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/agents/wiki-compiler.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/claude.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/copilot.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/cli/opencode.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/brainstorm.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/debug.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/commands/review.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-claude.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-copilot.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/global-opencode.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/hooks/session-context.md.tpl +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-haiku-4-5.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-1.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-5.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-6.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-7.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-8.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-5.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-6.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/claude.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode-index.js.template +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/orchestrator.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/reasoner.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/scout.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/roles/worker.yaml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/rules/code-quality.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/rules/safety.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/brainstorming/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/caveman/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/debugging-protocol/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/compose.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/dockerfile.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/git/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-me/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-with-docs/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/handoff/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/ingest/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/obsidian-memory/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/LOGIC.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/UI.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/controllers.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/frontend.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/infra.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/models.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/testing.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/views.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/setup-project-context/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/tdd/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-issues/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-prd/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/write-a-skill/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/zoom-out/SKILL.md +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/claude.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/opencode.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/doctor_checks.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/agent.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/cli_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/diagnostics.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/diff.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/model.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/role.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/rule.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/skill.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/domain/state.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/_base.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/agent_registry.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/cli_registry.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/model_registry.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/role_registry.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/registries/rule_registry.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/_pricing.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/scripts/cost_report.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/_memory_utils.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/counts.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/credentials.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_checks.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_display.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_fix.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/diff.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/fs.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/install_state_builder.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/installer.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/local_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/memory_router.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/migrations/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/obsidian_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/session_context.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/settings_writer.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/state_store.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/ui.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/user_config.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/validation.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/_wiki_utils.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_index.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_ingest.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_lint.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_query.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_storage.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/services/wiki_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/dependency_links.txt +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/entry_points.txt +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/requires.txt +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes.egg-info/top_level.txt +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/pyproject.toml +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/setup.cfg +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/conftest.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_config_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_info_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_install_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_list_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_regenerate_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_uninstall_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/commands/test_validate_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/memory/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/memory/test_memory_command.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/scripts/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/functional/scripts/test_release_script.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/build_output/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/build_output/test_build_output.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/install/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/install/test_install_methods.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/test_plugin_builders.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/claude/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/plugins/claude/test_agents.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_cost_report_subcommand.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_count_agents.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_info.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_add_description.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_imports.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_migrate.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_imports.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_orchestrator_skip.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_preflight.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_steps.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/commands/wizard/test_cost_report_step.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/registries/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report_scoping.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_formatting_tty.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/scripts/test_time_aggregation.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/__init__.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_build_functions.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_credential_filter.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_credentials.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_fs.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_hooks.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_plan.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_local_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend_io.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_router.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_session_context.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_settings_writer.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_skill_filtering.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_state_store.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_user_config_cost_report.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_validation.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_backend.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_imports.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/test_import_health.py +0 -0
- {agent_notes-2.25.0 → agent_notes-2.27.0}/tests/unit/test_memory_dir_for_backend.py +0 -0
|
@@ -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
|
-
|
|
49
|
-
print("
|
|
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
|
+
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).
|
|
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.
|
|
13
|
-
11.
|
|
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 match → forbidden 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
|
|
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.
|
|
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 (
|
|
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,
|
|
5
|
+
requires_memory: obsidian,wiki
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Migrate Memory
|
{agent_notes-2.25.0 → agent_notes-2.27.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md
RENAMED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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()
|
|
@@ -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
|