@event4u/agent-config 1.15.0 → 1.17.0

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 (354) hide show
  1. package/.agent-src/commands/{agents-audit.md → agents/audit.md} +4 -3
  2. package/.agent-src/commands/{agents-cleanup.md → agents/cleanup.md} +12 -6
  3. package/.agent-src/commands/{agents-prepare.md → agents/prepare.md} +4 -3
  4. package/.agent-src/commands/agents.md +46 -0
  5. package/.agent-src/commands/bug-fix.md +1 -1
  6. package/.agent-src/commands/bug-investigate.md +2 -2
  7. package/.agent-src/commands/{chat-history-checkpoint.md → chat-history/checkpoint.md} +5 -5
  8. package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +5 -5
  9. package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
  10. package/.agent-src/commands/chat-history/show.md +107 -0
  11. package/.agent-src/commands/chat-history.md +33 -89
  12. package/.agent-src/commands/check-current-md.md +1 -1
  13. package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
  14. package/.agent-src/commands/commit.md +22 -2
  15. package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
  16. package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
  17. package/.agent-src/commands/context.md +44 -0
  18. package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
  19. package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
  20. package/.agent-src/commands/copilot-agents.md +44 -0
  21. package/.agent-src/commands/council/default.md +221 -0
  22. package/.agent-src/commands/council/design.md +97 -0
  23. package/.agent-src/commands/council/optimize.md +116 -0
  24. package/.agent-src/commands/council/pr.md +124 -0
  25. package/.agent-src/commands/council.md +54 -0
  26. package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
  27. package/.agent-src/commands/create-pr.md +49 -5
  28. package/.agent-src/commands/e2e-heal.md +1 -1
  29. package/.agent-src/commands/e2e-plan.md +1 -1
  30. package/.agent-src/commands/{feature-dev.md → feature/dev.md} +6 -3
  31. package/.agent-src/commands/{feature-explore.md → feature/explore.md} +5 -4
  32. package/.agent-src/commands/{feature-plan.md → feature/plan.md} +32 -5
  33. package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -3
  34. package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +7 -6
  35. package/.agent-src/commands/feature.md +52 -0
  36. package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -3
  37. package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -3
  38. package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -3
  39. package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -3
  40. package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -6
  41. package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -3
  42. package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -3
  43. package/.agent-src/commands/fix.md +54 -0
  44. package/.agent-src/commands/jira-ticket.md +1 -1
  45. package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +7 -6
  46. package/.agent-src/commands/judge/solo.md +90 -0
  47. package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +8 -7
  48. package/.agent-src/commands/judge.md +35 -70
  49. package/.agent-src/commands/{memory-add.md → memory/add.md} +7 -6
  50. package/.agent-src/commands/{memory-full.md → memory/load.md} +6 -5
  51. package/.agent-src/commands/{memory-promote.md → memory/promote.md} +6 -5
  52. package/.agent-src/commands/{propose-memory.md → memory/propose.md} +6 -5
  53. package/.agent-src/commands/memory.md +48 -0
  54. package/.agent-src/commands/mode.md +5 -5
  55. package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
  56. package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
  57. package/.agent-src/commands/module.md +44 -0
  58. package/.agent-src/commands/onboard.md +3 -3
  59. package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +5 -4
  60. package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -4
  61. package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -3
  62. package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +5 -4
  63. package/.agent-src/commands/optimize.md +48 -0
  64. package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
  65. package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
  66. package/.agent-src/commands/override.md +44 -0
  67. package/.agent-src/commands/review-changes.md +26 -1
  68. package/.agent-src/commands/review-routing.md +1 -1
  69. package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +33 -5
  70. package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
  71. package/.agent-src/commands/roadmap.md +44 -0
  72. package/.agent-src/commands/set-cost-profile.md +3 -3
  73. package/.agent-src/commands/sync-agent-settings.md +2 -2
  74. package/.agent-src/commands/{tests-create.md → tests/create.md} +5 -4
  75. package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
  76. package/.agent-src/commands/tests.md +44 -0
  77. package/.agent-src/commands/upstream-contribute.md +1 -1
  78. package/.agent-src/contexts/authority/commit-mechanics.md +57 -0
  79. package/.agent-src/contexts/authority/destructive-mechanics.md +66 -0
  80. package/.agent-src/contexts/authority/scope-mechanics.md +87 -0
  81. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
  82. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
  83. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
  84. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
  85. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
  86. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
  87. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
  88. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
  89. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
  90. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
  91. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
  92. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
  93. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
  94. package/.agent-src/contexts/execution/autonomy-detection.md +54 -0
  95. package/.agent-src/contexts/execution/autonomy-examples.md +90 -0
  96. package/.agent-src/contexts/execution/autonomy-mechanics.md +29 -0
  97. package/.agent-src/contexts/execution/verification-mechanics.md +80 -0
  98. package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
  99. package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
  100. package/.agent-src/personas/README.md +1 -1
  101. package/.agent-src/rules/agent-authority.md +24 -0
  102. package/.agent-src/rules/architecture.md +1 -1
  103. package/.agent-src/rules/artifact-drafting-protocol.md +1 -1
  104. package/.agent-src/rules/artifact-engagement-recording.md +14 -70
  105. package/.agent-src/rules/ask-when-uncertain.md +28 -43
  106. package/.agent-src/rules/augment-portability.md +15 -61
  107. package/.agent-src/rules/augment-source-of-truth.md +27 -93
  108. package/.agent-src/rules/autonomous-execution.md +78 -114
  109. package/.agent-src/rules/capture-learnings.md +1 -1
  110. package/.agent-src/rules/chat-history-cadence.md +3 -3
  111. package/.agent-src/rules/chat-history-ownership.md +3 -3
  112. package/.agent-src/rules/chat-history-visibility.md +3 -3
  113. package/.agent-src/rules/cli-output-handling.md +10 -76
  114. package/.agent-src/rules/command-suggestion-policy.md +93 -0
  115. package/.agent-src/rules/commit-conventions.md +17 -14
  116. package/.agent-src/rules/commit-policy.md +14 -42
  117. package/.agent-src/rules/context-hygiene.md +3 -3
  118. package/.agent-src/rules/direct-answers.md +34 -49
  119. package/.agent-src/rules/docker-commands.md +5 -5
  120. package/.agent-src/rules/docs-sync.md +16 -70
  121. package/.agent-src/rules/e2e-testing.md +1 -1
  122. package/.agent-src/rules/guidelines.md +4 -4
  123. package/.agent-src/rules/improve-before-implement.md +2 -2
  124. package/.agent-src/rules/language-and-tone.md +50 -133
  125. package/.agent-src/rules/minimal-safe-diff.md +3 -3
  126. package/.agent-src/rules/missing-tool-handling.md +28 -22
  127. package/.agent-src/rules/model-recommendation.md +4 -4
  128. package/.agent-src/rules/no-cheap-questions.md +82 -0
  129. package/.agent-src/rules/no-roadmap-references.md +73 -0
  130. package/.agent-src/rules/non-destructive-by-default.md +15 -49
  131. package/.agent-src/rules/onboarding-gate.md +5 -5
  132. package/.agent-src/rules/package-ci-checks.md +21 -61
  133. package/.agent-src/rules/preservation-guard.md +64 -29
  134. package/.agent-src/rules/review-routing-awareness.md +26 -45
  135. package/.agent-src/rules/roadmap-progress-sync.md +28 -96
  136. package/.agent-src/rules/role-mode-adherence.md +2 -2
  137. package/.agent-src/rules/scope-control.md +65 -46
  138. package/.agent-src/rules/security-sensitive-stop.md +9 -9
  139. package/.agent-src/rules/size-enforcement.md +1 -1
  140. package/.agent-src/rules/skill-quality.md +16 -48
  141. package/.agent-src/rules/{slash-commands.md → slash-command-routing-policy.md} +7 -4
  142. package/.agent-src/rules/think-before-action.md +55 -45
  143. package/.agent-src/rules/token-efficiency.md +4 -4
  144. package/.agent-src/rules/tool-safety.md +19 -16
  145. package/.agent-src/rules/{ui-audit-before-build.md → ui-audit-gate.md} +27 -41
  146. package/.agent-src/rules/user-interaction.md +16 -71
  147. package/.agent-src/rules/verify-before-complete.md +12 -67
  148. package/.agent-src/scripts/update_roadmap_progress.py +9 -4
  149. package/.agent-src/skills/ai-council/SKILL.md +335 -0
  150. package/.agent-src/skills/api-endpoint/SKILL.md +2 -2
  151. package/.agent-src/skills/api-testing/SKILL.md +1 -1
  152. package/.agent-src/skills/blade-ui/SKILL.md +1 -1
  153. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  154. package/.agent-src/skills/bug-analyzer/SKILL.md +1 -1
  155. package/.agent-src/skills/check-refs/SKILL.md +59 -40
  156. package/.agent-src/skills/command-routing/SKILL.md +1 -1
  157. package/.agent-src/skills/command-writing/SKILL.md +1 -1
  158. package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
  159. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +7 -7
  160. package/.agent-src/skills/developer-like-execution/SKILL.md +6 -6
  161. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
  162. package/.agent-src/skills/flux/SKILL.md +31 -11
  163. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  164. package/.agent-src/skills/github-ci/SKILL.md +2 -2
  165. package/.agent-src/skills/guideline-writing/SKILL.md +11 -11
  166. package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
  167. package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
  168. package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
  169. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +4 -4
  170. package/.agent-src/skills/lint-skills/SKILL.md +57 -39
  171. package/.agent-src/skills/livewire/SKILL.md +1 -1
  172. package/.agent-src/skills/md-language-check/SKILL.md +61 -39
  173. package/.agent-src/skills/override-management/SKILL.md +7 -7
  174. package/.agent-src/skills/php-coder/SKILL.md +1 -1
  175. package/.agent-src/skills/playwright-testing/SKILL.md +2 -2
  176. package/.agent-src/skills/quality-tools/SKILL.md +2 -2
  177. package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
  178. package/.agent-src/skills/readme-reviewer/SKILL.md +31 -30
  179. package/.agent-src/skills/readme-writing/SKILL.md +79 -54
  180. package/.agent-src/skills/readme-writing-package/SKILL.md +51 -48
  181. package/.agent-src/skills/receiving-code-review/SKILL.md +53 -48
  182. package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
  183. package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
  184. package/.agent-src/skills/review-routing/SKILL.md +2 -2
  185. package/.agent-src/skills/rule-writing/SKILL.md +1 -1
  186. package/.agent-src/skills/security/SKILL.md +7 -2
  187. package/.agent-src/skills/security-audit/SKILL.md +7 -3
  188. package/.agent-src/skills/skill-reviewer/SKILL.md +1 -1
  189. package/.agent-src/skills/skill-writing/SKILL.md +3 -3
  190. package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -0
  191. package/.agent-src/skills/systematic-debugging/SKILL.md +69 -61
  192. package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
  193. package/.agent-src/skills/test-performance/SKILL.md +0 -1
  194. package/.agent-src/skills/traefik/SKILL.md +4 -4
  195. package/.agent-src/skills/upstream-contribute/SKILL.md +1 -1
  196. package/.agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  197. package/.agent-src/skills/{verify-before-complete → verify-completion-evidence}/SKILL.md +30 -28
  198. package/.agent-src/templates/agent-settings.md +8 -8
  199. package/.agent-src/templates/contexts/auth-model.md +1 -1
  200. package/.agent-src/templates/scripts/README.md +2 -2
  201. package/.agent-src/templates/scripts/telemetry/aggregator.py +16 -1
  202. package/.agent-src/templates/scripts/telemetry/engagement.py +59 -0
  203. package/.agent-src/templates/scripts/telemetry/report_renderer.py +28 -1
  204. package/.agent-src/templates/scripts/telemetry_record.py +14 -1
  205. package/.claude-plugin/marketplace.json +31 -12
  206. package/AGENTS.md +11 -9
  207. package/CHANGELOG.md +213 -2
  208. package/README.md +43 -44
  209. package/config/agent-settings.template.yml +58 -1
  210. package/config/gitignore-block.txt +3 -0
  211. package/docs/architecture.md +5 -7
  212. package/docs/catalog.md +359 -0
  213. package/docs/contracts/STABILITY.md +46 -1
  214. package/docs/contracts/adr-chat-history-split.md +1 -3
  215. package/docs/contracts/adr-command-suggestion.md +3 -5
  216. package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
  217. package/docs/contracts/adr-product-ui-track.md +5 -8
  218. package/docs/contracts/adr-prompt-driven-execution.md +3 -4
  219. package/docs/contracts/agent-memory-contract.md +8 -13
  220. package/docs/contracts/artifact-engagement-flow.md +7 -10
  221. package/docs/contracts/command-clusters.md +56 -46
  222. package/docs/contracts/command-suggestion-flow.md +4 -6
  223. package/docs/contracts/context-paths.md +99 -0
  224. package/docs/contracts/file-ownership-matrix.json +6722 -0
  225. package/docs/contracts/file-ownership-matrix.md +134 -0
  226. package/docs/contracts/implement-ticket-flow.md +8 -11
  227. package/docs/contracts/linear-ai-rules-inclusion.md +1 -2
  228. package/docs/contracts/linear-ai-three-layers.md +0 -2
  229. package/docs/contracts/load-context-budget-model.md +178 -0
  230. package/docs/contracts/load-context-schema.md +184 -0
  231. package/docs/contracts/rule-interactions.md +0 -1
  232. package/docs/contracts/rule-interactions.yml +96 -0
  233. package/docs/contracts/rule-priority-hierarchy.md +87 -0
  234. package/docs/contracts/ui-track-flow.md +8 -18
  235. package/docs/customization.md +16 -0
  236. package/docs/end-to-end-walkthroughs.md +165 -0
  237. package/docs/getting-started.md +29 -10
  238. package/docs/github-topics.md +12 -3
  239. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
  240. package/docs/guidelines/agent-infra/language-and-tone-examples.md +79 -0
  241. package/{.agent-src → docs}/guidelines/docs/readme-size-and-splitting.md +26 -25
  242. package/docs/guidelines/php/git.md +164 -0
  243. package/docs/migrations/commands-1.15.0.md +1 -1
  244. package/docs/showcase.md +9 -4
  245. package/docs/skills-catalog.md +14 -8
  246. package/docs/ui-track-mental-model.md +2 -2
  247. package/llms.txt +13 -7
  248. package/package.json +1 -1
  249. package/scripts/_one_off_phase4_dispatch_latency.py +108 -0
  250. package/scripts/_one_off_phase6_trigger_jaccard.py +92 -0
  251. package/scripts/_phase2_shim_helper.py +109 -0
  252. package/scripts/agent-config +33 -0
  253. package/scripts/ai_council/__init__.py +39 -0
  254. package/scripts/ai_council/_default_prices.py +41 -0
  255. package/scripts/ai_council/_one_off_2a4_acceptance.py +208 -0
  256. package/scripts/ai_council/_one_off_context_layer_v1_estimate.py +67 -0
  257. package/scripts/ai_council/_one_off_context_layer_v1_review.py +292 -0
  258. package/scripts/ai_council/_one_off_followups_review.py +259 -0
  259. package/scripts/ai_council/_one_off_nondestructive_inline_audit.py +209 -0
  260. package/scripts/ai_council/_one_off_phase_2a_budget_rebalance.py +257 -0
  261. package/scripts/ai_council/_one_off_phase_2a_post_revert.py +197 -0
  262. package/scripts/ai_council/_one_off_rebalancing_audit.py +149 -0
  263. package/scripts/ai_council/_one_off_roundtrip.py +106 -0
  264. package/scripts/ai_council/_one_off_rule_hardening_v1.py +251 -0
  265. package/scripts/ai_council/_one_off_structural_open_questions.py +232 -0
  266. package/scripts/ai_council/_one_off_structural_optimization.py +144 -0
  267. package/scripts/ai_council/_one_off_structural_v3_gaps.py +252 -0
  268. package/scripts/ai_council/_one_off_structural_v3_review.py +240 -0
  269. package/scripts/ai_council/budget_guard.py +172 -0
  270. package/scripts/ai_council/bundler.py +261 -0
  271. package/scripts/ai_council/clients.py +381 -0
  272. package/scripts/ai_council/modes.py +127 -0
  273. package/scripts/ai_council/orchestrator.py +350 -0
  274. package/scripts/ai_council/pricing.py +213 -0
  275. package/scripts/ai_council/project_context.py +159 -0
  276. package/scripts/ai_council/prompts.py +232 -0
  277. package/scripts/ai_council/session.py +144 -0
  278. package/scripts/check_always_budget.py +444 -0
  279. package/scripts/check_augmentignore.py +69 -0
  280. package/scripts/check_cluster_patterns.py +159 -0
  281. package/scripts/check_command_count_messaging.py +127 -0
  282. package/scripts/check_context_paths.py +201 -0
  283. package/scripts/check_no_roadmap_refs.py +155 -0
  284. package/scripts/check_phase_coupling.py +148 -0
  285. package/scripts/check_portability.py +57 -0
  286. package/scripts/check_public_catalog_links.py +122 -0
  287. package/scripts/check_references.py +33 -3
  288. package/scripts/check_roadmap_trackable.py +111 -0
  289. package/scripts/check_safety_floor_untouched.py +125 -0
  290. package/scripts/command_suggester/cooldown.py +1 -1
  291. package/scripts/command_suggester/loader.py +4 -1
  292. package/scripts/compress.py +59 -13
  293. package/scripts/generate_index.py +270 -0
  294. package/scripts/generate_ownership_matrix.py +323 -0
  295. package/scripts/hooks/augment-roadmap-progress.sh +57 -0
  296. package/scripts/install.py +49 -28
  297. package/scripts/install_anthropic_key.sh +5 -0
  298. package/scripts/install_openai_key.sh +106 -0
  299. package/scripts/lint_load_context.py +163 -0
  300. package/scripts/lint_no_new_atomic_commands.py +12 -11
  301. package/scripts/requirements-evals.txt +1 -0
  302. package/scripts/roadmap_progress_hook.py +159 -0
  303. package/scripts/schemas/command.schema.json +22 -1
  304. package/scripts/schemas/rule.schema.json +10 -0
  305. package/scripts/skill_linter.py +13 -4
  306. package/scripts/sync_agent_settings.py +26 -3
  307. package/scripts/update_counts.py +16 -4
  308. package/scripts/update_prices.py +124 -0
  309. package/.agent-src/guidelines/php/git.md +0 -96
  310. package/.agent-src/rules/command-suggestion.md +0 -134
  311. /package/{.agent-src → docs}/guidelines/agent-infra/agent-interaction-and-decision-quality.md +0 -0
  312. /package/{.agent-src → docs}/guidelines/agent-infra/break-glass-usage.md +0 -0
  313. /package/{.agent-src → docs}/guidelines/agent-infra/developer-judgment.md +0 -0
  314. /package/{.agent-src → docs}/guidelines/agent-infra/engineering-memory-data-format.md +0 -0
  315. /package/{.agent-src → docs}/guidelines/agent-infra/layered-settings.md +0 -0
  316. /package/{.agent-src → docs}/guidelines/agent-infra/memory-access.md +0 -0
  317. /package/{.agent-src → docs}/guidelines/agent-infra/naming.md +0 -0
  318. /package/{.agent-src → docs}/guidelines/agent-infra/output-patterns.md +0 -0
  319. /package/{.agent-src → docs}/guidelines/agent-infra/review-routing-data-format.md +0 -0
  320. /package/{.agent-src → docs}/guidelines/agent-infra/role-contracts.md +0 -0
  321. /package/{.agent-src → docs}/guidelines/agent-infra/role-mode-router.md +0 -0
  322. /package/{.agent-src → docs}/guidelines/agent-infra/runtime-layer.md +0 -0
  323. /package/{.agent-src → docs}/guidelines/agent-infra/self-improvement-pipeline.md +0 -0
  324. /package/{.agent-src → docs}/guidelines/agent-infra/size-and-scope.md +0 -0
  325. /package/{.agent-src → docs}/guidelines/agent-infra/tool-integration.md +0 -0
  326. /package/{.agent-src → docs}/guidelines/e2e/playwright.md +0 -0
  327. /package/{.agent-src → docs}/guidelines/php/api-design.md +0 -0
  328. /package/{.agent-src → docs}/guidelines/php/artisan-commands.md +0 -0
  329. /package/{.agent-src → docs}/guidelines/php/blade-ui.md +0 -0
  330. /package/{.agent-src → docs}/guidelines/php/controllers.md +0 -0
  331. /package/{.agent-src → docs}/guidelines/php/database.md +0 -0
  332. /package/{.agent-src → docs}/guidelines/php/eloquent.md +0 -0
  333. /package/{.agent-src → docs}/guidelines/php/flux.md +0 -0
  334. /package/{.agent-src → docs}/guidelines/php/general.md +0 -0
  335. /package/{.agent-src → docs}/guidelines/php/jobs.md +0 -0
  336. /package/{.agent-src → docs}/guidelines/php/livewire.md +0 -0
  337. /package/{.agent-src → docs}/guidelines/php/logging.md +0 -0
  338. /package/{.agent-src → docs}/guidelines/php/naming.md +0 -0
  339. /package/{.agent-src → docs}/guidelines/php/patterns/dependency-injection.md +0 -0
  340. /package/{.agent-src → docs}/guidelines/php/patterns/dtos.md +0 -0
  341. /package/{.agent-src → docs}/guidelines/php/patterns/events.md +0 -0
  342. /package/{.agent-src → docs}/guidelines/php/patterns/factory.md +0 -0
  343. /package/{.agent-src → docs}/guidelines/php/patterns/pipelines.md +0 -0
  344. /package/{.agent-src → docs}/guidelines/php/patterns/policies.md +0 -0
  345. /package/{.agent-src → docs}/guidelines/php/patterns/repositories.md +0 -0
  346. /package/{.agent-src → docs}/guidelines/php/patterns/service-layer.md +0 -0
  347. /package/{.agent-src → docs}/guidelines/php/patterns/strategy.md +0 -0
  348. /package/{.agent-src → docs}/guidelines/php/patterns.md +0 -0
  349. /package/{.agent-src → docs}/guidelines/php/performance.md +0 -0
  350. /package/{.agent-src → docs}/guidelines/php/resources.md +0 -0
  351. /package/{.agent-src → docs}/guidelines/php/security.md +0 -0
  352. /package/{.agent-src → docs}/guidelines/php/sql.md +0 -0
  353. /package/{.agent-src → docs}/guidelines/php/validations.md +0 -0
  354. /package/{.agent-src → docs}/guidelines/php/websocket.md +0 -0
@@ -0,0 +1,381 @@
1
+ """External-AI clients for the council.
2
+
3
+ Mirrors the contract from `scripts/skill_trigger_eval.py`:
4
+ - Tokens come exclusively from ~/.config/agent-config/<provider>.key.
5
+ - File mode must be exactly 0o600. Drift is a hard abort.
6
+ - No environment-variable fallback. No keychain fallback.
7
+ - Real SDKs (`anthropic`, `openai`) are *soft* dependencies — the
8
+ module imports cleanly without them; only `ask()` requires them.
9
+
10
+ Tests inject mock clients via the `client=` constructor argument and
11
+ never hit the real API.
12
+
13
+ Mode contract (Phase 2b):
14
+ - `billable=True` clients (AnthropicClient, OpenAIClient) participate
15
+ in the cost gate — projected USD spend is checked before each call.
16
+ - `billable=False` clients (ManualClient, future PlaywrightClient)
17
+ skip the cost gate entirely. Spend = $0 to us; provider-side rate
18
+ limits are the user's concern.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import stat
24
+ import sys
25
+ import time
26
+ from abc import ABC, abstractmethod
27
+ from dataclasses import dataclass, field
28
+ from pathlib import Path
29
+ from typing import TextIO
30
+
31
+ ANTHROPIC_KEY_PATH = Path.home() / ".config" / "agent-config" / "anthropic.key"
32
+ OPENAI_KEY_PATH = Path.home() / ".config" / "agent-config" / "openai.key"
33
+
34
+ DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-5"
35
+ DEFAULT_OPENAI_MODEL = "gpt-4o"
36
+
37
+
38
+ class KeyGateError(RuntimeError):
39
+ """Raised when a provider key file violates the 0600 contract."""
40
+
41
+
42
+ @dataclass
43
+ class CouncilResponse:
44
+ """Normalised output from a single council member."""
45
+
46
+ provider: str
47
+ model: str
48
+ text: str
49
+ input_tokens: int = 0
50
+ output_tokens: int = 0
51
+ latency_ms: int = 0
52
+ error: str | None = None
53
+ metadata: dict[str, object] = field(default_factory=dict)
54
+
55
+
56
+ def _load_key(path: Path, prefix: str, install_script: str) -> str:
57
+ """Shared 0600-gated key loader. Refuses anything outside the contract."""
58
+ if not path.exists():
59
+ raise KeyGateError(
60
+ f"Key not found at {path}.\n"
61
+ f" Install it with: bash {install_script}"
62
+ )
63
+ st = path.stat()
64
+ mode = stat.S_IMODE(st.st_mode)
65
+ if mode != 0o600:
66
+ raise KeyGateError(
67
+ f"Unsafe permissions on {path}: got {oct(mode)}, expected 0o600.\n"
68
+ f" Fix: chmod 600 {path}"
69
+ )
70
+ key = path.read_text(encoding="utf-8").strip()
71
+ if not key:
72
+ raise KeyGateError(f"{path} is empty.")
73
+ if not key.startswith(prefix):
74
+ raise KeyGateError(
75
+ f"{path} does not look like a {prefix!r}-prefixed key."
76
+ )
77
+ return key
78
+
79
+
80
+ def load_anthropic_key(path: Path = ANTHROPIC_KEY_PATH) -> str:
81
+ return _load_key(path, "sk-ant-", "scripts/install_anthropic_key.sh")
82
+
83
+
84
+ def load_openai_key(path: Path = OPENAI_KEY_PATH) -> str:
85
+ return _load_key(path, "sk-", "scripts/install_openai_key.sh")
86
+
87
+
88
+ class ExternalAIClient(ABC):
89
+ """Abstract base for council members."""
90
+
91
+ name: str = ""
92
+ model: str = ""
93
+ billable: bool = True # API-mode subclasses spend money; manual/playwright don't.
94
+
95
+ @abstractmethod
96
+ def ask(
97
+ self,
98
+ system_prompt: str,
99
+ user_prompt: str,
100
+ max_tokens: int = 1024,
101
+ ) -> CouncilResponse:
102
+ """Send one independent query. Must never raise on network/API
103
+ failure — return a `CouncilResponse` with `error` set instead.
104
+ Other members should not be blocked by one failure."""
105
+
106
+
107
+ class AnthropicClient(ExternalAIClient):
108
+ name = "anthropic"
109
+ billable = True
110
+
111
+ def __init__(
112
+ self,
113
+ model: str = DEFAULT_ANTHROPIC_MODEL,
114
+ client: object = None,
115
+ api_key: str | None = None,
116
+ ):
117
+ self.model = model
118
+ if client is not None:
119
+ self._client = client
120
+ return
121
+ if api_key is None:
122
+ raise RuntimeError(
123
+ "AnthropicClient requires explicit api_key or injected client. "
124
+ "Use load_anthropic_key() — no env-var fallback."
125
+ )
126
+ try:
127
+ import anthropic # type: ignore[import-not-found]
128
+ except ImportError as exc: # pragma: no cover - exercised only with real SDK
129
+ raise RuntimeError(
130
+ "anthropic package not installed. `pip install anthropic`."
131
+ ) from exc
132
+ self._client = anthropic.Anthropic(api_key=api_key)
133
+
134
+ def ask(self, system_prompt: str, user_prompt: str, max_tokens: int = 1024) -> CouncilResponse:
135
+ t0 = time.monotonic()
136
+ try:
137
+ response = self._client.messages.create(
138
+ model=self.model,
139
+ max_tokens=max_tokens,
140
+ system=system_prompt,
141
+ messages=[{"role": "user", "content": user_prompt}],
142
+ )
143
+ except Exception as exc: # noqa: BLE001 - normalise all SDK errors
144
+ return CouncilResponse(
145
+ provider=self.name, model=self.model, text="",
146
+ latency_ms=int((time.monotonic() - t0) * 1000),
147
+ error=f"{type(exc).__name__}: {exc}",
148
+ )
149
+ latency_ms = int((time.monotonic() - t0) * 1000)
150
+ text = ""
151
+ content = getattr(response, "content", None)
152
+ if content:
153
+ text = getattr(content[0], "text", "") or ""
154
+ usage = getattr(response, "usage", None)
155
+ return CouncilResponse(
156
+ provider=self.name, model=self.model, text=text,
157
+ input_tokens=getattr(usage, "input_tokens", 0) if usage else 0,
158
+ output_tokens=getattr(usage, "output_tokens", 0) if usage else 0,
159
+ latency_ms=latency_ms,
160
+ )
161
+
162
+
163
+ class OpenAIClient(ExternalAIClient):
164
+ name = "openai"
165
+ billable = True
166
+
167
+ def __init__(
168
+ self,
169
+ model: str = DEFAULT_OPENAI_MODEL,
170
+ client: object = None,
171
+ api_key: str | None = None,
172
+ ):
173
+ self.model = model
174
+ if client is not None:
175
+ self._client = client
176
+ return
177
+ if api_key is None:
178
+ raise RuntimeError(
179
+ "OpenAIClient requires explicit api_key or injected client. "
180
+ "Use load_openai_key() — no env-var fallback."
181
+ )
182
+ try:
183
+ import openai # type: ignore[import-not-found]
184
+ except ImportError as exc: # pragma: no cover - exercised only with real SDK
185
+ raise RuntimeError(
186
+ "openai package not installed. `pip install openai`."
187
+ ) from exc
188
+ self._client = openai.OpenAI(api_key=api_key)
189
+
190
+ def ask(self, system_prompt: str, user_prompt: str, max_tokens: int = 1024) -> CouncilResponse:
191
+ t0 = time.monotonic()
192
+ try:
193
+ response = self._client.chat.completions.create(
194
+ model=self.model,
195
+ max_tokens=max_tokens,
196
+ messages=[
197
+ {"role": "system", "content": system_prompt},
198
+ {"role": "user", "content": user_prompt},
199
+ ],
200
+ )
201
+ except Exception as exc: # noqa: BLE001 - normalise all SDK errors
202
+ return CouncilResponse(
203
+ provider=self.name, model=self.model, text="",
204
+ latency_ms=int((time.monotonic() - t0) * 1000),
205
+ error=f"{type(exc).__name__}: {exc}",
206
+ )
207
+ latency_ms = int((time.monotonic() - t0) * 1000)
208
+ text = ""
209
+ choices = getattr(response, "choices", None)
210
+ if choices:
211
+ msg = getattr(choices[0], "message", None)
212
+ text = getattr(msg, "content", "") if msg else ""
213
+ usage = getattr(response, "usage", None)
214
+ return CouncilResponse(
215
+ provider=self.name, model=self.model, text=text or "",
216
+ input_tokens=getattr(usage, "prompt_tokens", 0) if usage else 0,
217
+ output_tokens=getattr(usage, "completion_tokens", 0) if usage else 0,
218
+ latency_ms=latency_ms,
219
+ )
220
+
221
+
222
+ # ── Manual mode (Phase 2b) ───────────────────────────────────────────
223
+
224
+
225
+ MANUAL_END_MARKER = "END" # line containing only this terminates a paste block.
226
+
227
+
228
+ def _read_until_marker(stream: TextIO, marker: str) -> str:
229
+ """Read lines from `stream` until a line equal to `marker` (after strip).
230
+
231
+ Returns the joined body without the marker line. EOF before the
232
+ marker is treated as end-of-input — the body collected so far is
233
+ returned; callers decide whether that counts as abort.
234
+ """
235
+ body: list[str] = []
236
+ for raw in stream:
237
+ line = raw.rstrip("\n")
238
+ if line.strip() == marker:
239
+ break
240
+ body.append(line)
241
+ return "\n".join(body).strip()
242
+
243
+
244
+ class ManualClient(ExternalAIClient):
245
+ """Copy-paste council member — user is the transport.
246
+
247
+ `ask()` renders the system prompt + artefact as one Markdown block,
248
+ prints it to `stdout`, and reads pasted replies from `stdin`. After
249
+ each pasted reply, surfaces a 1/2/3 menu (more · next · abort) per
250
+ `user-interaction`. Loops until the user picks 2 or 3.
251
+
252
+ Spend is $0 — `billable=False` makes the orchestrator skip the cost
253
+ gate for this member regardless of the price table.
254
+
255
+ Tests inject `stdin` / `stdout` `TextIO` streams. Production usage
256
+ falls back to `sys.stdin` / `sys.stdout`.
257
+ """
258
+
259
+ billable = False
260
+
261
+ def __init__(
262
+ self,
263
+ *,
264
+ name: str = "manual",
265
+ model: str = "manual",
266
+ provider_label: str = "your LLM web UI",
267
+ stdin: TextIO | None = None,
268
+ stdout: TextIO | None = None,
269
+ end_marker: str = MANUAL_END_MARKER,
270
+ ):
271
+ self.name = name
272
+ self.model = model
273
+ self.provider_label = provider_label
274
+ self._stdin = stdin if stdin is not None else sys.stdin
275
+ self._stdout = stdout if stdout is not None else sys.stdout
276
+ self._end_marker = end_marker
277
+
278
+ def ask(
279
+ self,
280
+ system_prompt: str,
281
+ user_prompt: str,
282
+ max_tokens: int = 1024, # noqa: ARG002 — accepted for ABC parity
283
+ ) -> CouncilResponse:
284
+ t0 = time.monotonic()
285
+ rounds: list[str] = []
286
+ block = self._render_block(system_prompt, user_prompt, follow_up=None)
287
+ self._emit(block)
288
+
289
+ try:
290
+ while True:
291
+ reply = _read_until_marker(self._stdin, self._end_marker)
292
+ rounds.append(reply)
293
+ choice = self._ask_menu(reply_chars=len(reply))
294
+
295
+ if choice == "2": # done with this member
296
+ break
297
+ if choice == "3": # abort the council run
298
+ return CouncilResponse(
299
+ provider=self.name, model=self.model, text="",
300
+ latency_ms=int((time.monotonic() - t0) * 1000),
301
+ error="manual_aborted",
302
+ metadata={"rounds": len(rounds), "manual": True},
303
+ )
304
+ # choice == "1": collect follow-up, re-emit context block.
305
+ follow_up = self._read_follow_up()
306
+ if not follow_up:
307
+ break # empty follow-up → treat as "done with this member"
308
+ rounds.append(f"[follow-up sent]\n{follow_up}")
309
+ block = self._render_block(system_prompt, user_prompt, follow_up=follow_up)
310
+ self._emit(block)
311
+ except Exception as exc: # noqa: BLE001 — never break the council on a stdin glitch
312
+ return CouncilResponse(
313
+ provider=self.name, model=self.model, text="\n\n".join(rounds),
314
+ latency_ms=int((time.monotonic() - t0) * 1000),
315
+ error=f"{type(exc).__name__}: {exc}",
316
+ metadata={"rounds": len(rounds), "manual": True},
317
+ )
318
+
319
+ text = "\n\n---\n\n".join(rounds).strip()
320
+ return CouncilResponse(
321
+ provider=self.name, model=self.model, text=text,
322
+ latency_ms=int((time.monotonic() - t0) * 1000),
323
+ metadata={"rounds": len(rounds), "manual": True},
324
+ )
325
+
326
+ # ── helpers ──────────────────────────────────────────────────────
327
+
328
+ def _emit(self, text: str) -> None:
329
+ self._stdout.write(text)
330
+ self._stdout.write("\n")
331
+ self._stdout.flush()
332
+
333
+ def _render_block(
334
+ self,
335
+ system_prompt: str,
336
+ user_prompt: str,
337
+ *,
338
+ follow_up: str | None,
339
+ ) -> str:
340
+ bar = "═" * 67
341
+ head = (
342
+ f"{bar}\n"
343
+ f"Manual council member: {self.provider_label}\n"
344
+ f"Paste this block into the web UI · then paste the reply below.\n"
345
+ f"{bar}"
346
+ )
347
+ if follow_up is not None:
348
+ body = (
349
+ f"[Follow-up — paste this into the SAME chat thread]\n\n"
350
+ f"{follow_up}"
351
+ )
352
+ else:
353
+ body = f"{system_prompt}\n\n---\n\n{user_prompt}"
354
+ tail = (
355
+ f"{bar}\n"
356
+ f"End your pasted reply with a line containing only: {self._end_marker}\n"
357
+ f"{bar}"
358
+ )
359
+ return f"{head}\n\n{body}\n\n{tail}"
360
+
361
+ def _ask_menu(self, *, reply_chars: int) -> str:
362
+ prompt = (
363
+ f"\nReply received ({reply_chars} chars). Now what?\n"
364
+ f" 1. More feedback for this member (continue this thread)\n"
365
+ f" 2. Done with this member, move to the next\n"
366
+ f" 3. Abort the council run\n\n"
367
+ f"Choose 1/2/3: "
368
+ )
369
+ self._stdout.write(prompt)
370
+ self._stdout.flush()
371
+ line = self._stdin.readline().strip()
372
+ if line in {"1", "2", "3"}:
373
+ return line
374
+ # unknown input → treat as "next" so we never block forever in tests / piped runs.
375
+ return "2"
376
+
377
+ def _read_follow_up(self) -> str:
378
+ self._emit(
379
+ f"\nType your follow-up question, end with a line containing only: {self._end_marker}"
380
+ )
381
+ return _read_until_marker(self._stdin, self._end_marker)
@@ -0,0 +1,127 @@
1
+ """Mode resolution for council members (Phase 2b).
2
+
3
+ Each council member runs in exactly one transport mode per invocation:
4
+
5
+ - ``api`` — direct SDK call against the provider's API (billable).
6
+ - ``manual`` — copy-paste loop with the user as transport (free).
7
+ - ``playwright`` — browser automation (Phase 2c, not yet wired).
8
+
9
+ Resolution precedence — first non-empty wins:
10
+
11
+ 1. Invocation flag e.g. ``/council mode:manual``
12
+ 2. Per-member setting ``ai_council.members.<name>.mode``
13
+ 3. Global setting ``ai_council.mode``
14
+ 4. Built-in default ``api``
15
+
16
+ This mirrors how ``cost_profile`` resolves in
17
+ ``.augment/guidelines/agent-infra/layered-settings.md``.
18
+
19
+ The resolver is pure — it never touches the filesystem or environment.
20
+ Callers pass in already-loaded values from ``.agent-settings.yml``.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from typing import Mapping
26
+
27
+ VALID_MODES: frozenset[str] = frozenset({"api", "manual", "playwright"})
28
+
29
+ DEFAULT_MODE: str = "api"
30
+
31
+
32
+ class InvalidModeError(ValueError):
33
+ """Raised when a configured / invoked mode is not in ``VALID_MODES``."""
34
+
35
+
36
+ def _normalise(value: object) -> str | None:
37
+ if value is None:
38
+ return None
39
+ if not isinstance(value, str):
40
+ return None
41
+ s = value.strip().lower()
42
+ return s or None
43
+
44
+
45
+ def _validate(mode: str | None, source: str) -> str | None:
46
+ if mode is None:
47
+ return None
48
+ if mode not in VALID_MODES:
49
+ raise InvalidModeError(
50
+ f"{source} requested mode={mode!r}; "
51
+ f"expected one of: {sorted(VALID_MODES)}"
52
+ )
53
+ return mode
54
+
55
+
56
+ def resolve_mode(
57
+ member_name: str,
58
+ *,
59
+ invocation_mode: str | None = None,
60
+ member_settings: Mapping[str, object] | None = None,
61
+ global_mode: str | None = None,
62
+ ) -> str:
63
+ """Resolve the effective transport mode for one member.
64
+
65
+ Args:
66
+ member_name: e.g. ``"anthropic"`` or ``"openai"``. Used in error
67
+ messages only — has no effect on precedence.
68
+ invocation_mode: from a ``/council mode:<x>`` flag. Highest
69
+ priority. ``None`` if the user did not pass a flag.
70
+ member_settings: the dict at
71
+ ``ai_council.members.<member_name>`` from
72
+ ``.agent-settings.yml``. May contain a ``mode`` key.
73
+ global_mode: from ``ai_council.mode``. Used when neither the
74
+ invocation flag nor the per-member setting is present.
75
+
76
+ Returns:
77
+ One of ``VALID_MODES``. Never ``None``.
78
+
79
+ Raises:
80
+ InvalidModeError: if any non-empty layer requests a mode not in
81
+ ``VALID_MODES``. The earliest layer (highest priority) is
82
+ checked first; later layers are not validated when an
83
+ earlier one already won.
84
+ """
85
+ inv = _validate(_normalise(invocation_mode), source=f"/council mode= for {member_name!r}")
86
+ if inv is not None:
87
+ return inv
88
+
89
+ member_mode_raw: object | None = None
90
+ if member_settings is not None:
91
+ member_mode_raw = member_settings.get("mode")
92
+ member = _validate(
93
+ _normalise(member_mode_raw),
94
+ source=f"ai_council.members.{member_name}.mode",
95
+ )
96
+ if member is not None:
97
+ return member
98
+
99
+ glob = _validate(_normalise(global_mode), source="ai_council.mode")
100
+ if glob is not None:
101
+ return glob
102
+
103
+ return DEFAULT_MODE
104
+
105
+
106
+ def resolve_modes(
107
+ member_names: list[str],
108
+ *,
109
+ invocation_mode: str | None = None,
110
+ members_settings: Mapping[str, Mapping[str, object]] | None = None,
111
+ global_mode: str | None = None,
112
+ ) -> dict[str, str]:
113
+ """Resolve modes for a batch of members. Convenience wrapper.
114
+
115
+ ``members_settings`` is the full ``ai_council.members`` mapping;
116
+ each member's sub-dict is forwarded to ``resolve_mode()``.
117
+ """
118
+ out: dict[str, str] = {}
119
+ settings = members_settings or {}
120
+ for name in member_names:
121
+ out[name] = resolve_mode(
122
+ name,
123
+ invocation_mode=invocation_mode,
124
+ member_settings=settings.get(name),
125
+ global_mode=global_mode,
126
+ )
127
+ return out