@event4u/agent-config 5.7.0 → 5.8.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 (162) hide show
  1. package/.agent-src/commands/agent-handoff.md +1 -1
  2. package/.agent-src/commands/agent-status.md +1 -1
  3. package/.agent-src/commands/agents/audit.md +1 -1
  4. package/.agent-src/commands/agents/init.md +1 -1
  5. package/.agent-src/commands/agents/user/accept.md +3 -3
  6. package/.agent-src/commands/agents/user/init.md +4 -4
  7. package/.agent-src/commands/agents/user/show.md +3 -3
  8. package/.agent-src/commands/agents/user/update.md +3 -3
  9. package/.agent-src/commands/agents/user.md +1 -1
  10. package/.agent-src/commands/agents.md +1 -1
  11. package/.agent-src/commands/analytics/prune.md +1 -1
  12. package/.agent-src/commands/analytics/show.md +1 -1
  13. package/.agent-src/commands/analytics.md +1 -1
  14. package/.agent-src/commands/bug-fix.md +1 -1
  15. package/.agent-src/commands/challenge-me.md +1 -1
  16. package/.agent-src/commands/chat-history/import.md +1 -1
  17. package/.agent-src/commands/chat-history/learn.md +1 -1
  18. package/.agent-src/commands/chat-history/show.md +1 -1
  19. package/.agent-src/commands/chat-history.md +1 -1
  20. package/.agent-src/commands/check-current-md.md +1 -1
  21. package/.agent-src/commands/condense.md +1 -1
  22. package/.agent-src/commands/context.md +1 -1
  23. package/.agent-src/commands/cost-report.md +1 -1
  24. package/.agent-src/commands/council.md +3 -3
  25. package/.agent-src/commands/create-pr/description-only.md +1 -1
  26. package/.agent-src/commands/create-pr.md +1 -1
  27. package/.agent-src/commands/e2e-heal.md +1 -1
  28. package/.agent-src/commands/e2e-plan.md +1 -1
  29. package/.agent-src/commands/feature.md +1 -1
  30. package/.agent-src/commands/fix/ci.md +1 -1
  31. package/.agent-src/commands/fix/portability.md +1 -1
  32. package/.agent-src/commands/fix/pr-bot-comments.md +1 -1
  33. package/.agent-src/commands/fix/pr-comments.md +1 -1
  34. package/.agent-src/commands/fix/pr-developer-comments.md +1 -1
  35. package/.agent-src/commands/fix/refs.md +1 -1
  36. package/.agent-src/commands/fix/seeder.md +1 -1
  37. package/.agent-src/commands/fix.md +1 -1
  38. package/.agent-src/commands/judge.md +1 -1
  39. package/.agent-src/commands/knowledge/cross-repo.md +1 -1
  40. package/.agent-src/commands/knowledge/forget.md +1 -1
  41. package/.agent-src/commands/knowledge/ingest.md +1 -1
  42. package/.agent-src/commands/knowledge/list.md +1 -1
  43. package/.agent-src/commands/knowledge.md +1 -1
  44. package/.agent-src/commands/memory/add.md +1 -1
  45. package/.agent-src/commands/memory/learn-low-impact.md +1 -1
  46. package/.agent-src/commands/memory/load.md +1 -1
  47. package/.agent-src/commands/memory/mine-session.md +1 -1
  48. package/.agent-src/commands/memory/promote.md +1 -1
  49. package/.agent-src/commands/memory/propose.md +1 -1
  50. package/.agent-src/commands/memory.md +1 -1
  51. package/.agent-src/commands/mode.md +1 -1
  52. package/.agent-src/commands/optimize/agents-dir.md +1 -1
  53. package/.agent-src/commands/optimize/augmentignore.md +1 -1
  54. package/.agent-src/commands/optimize/rtk.md +1 -1
  55. package/.agent-src/commands/optimize/skills.md +1 -1
  56. package/.agent-src/commands/optimize.md +1 -1
  57. package/.agent-src/commands/orchestrate.md +1 -1
  58. package/.agent-src/commands/override/create.md +1 -1
  59. package/.agent-src/commands/override/manage.md +1 -1
  60. package/.agent-src/commands/override.md +1 -1
  61. package/.agent-src/commands/package-reset.md +1 -1
  62. package/.agent-src/commands/prediction-pool.md +31 -12
  63. package/.agent-src/commands/profile/activate.md +81 -0
  64. package/.agent-src/commands/profile/deactivate.md +68 -0
  65. package/.agent-src/commands/profile/show.md +70 -0
  66. package/.agent-src/commands/profile.md +68 -0
  67. package/.agent-src/commands/project-health.md +1 -1
  68. package/.agent-src/commands/quality-fix.md +1 -1
  69. package/.agent-src/commands/roadmap/process-full.md +1 -1
  70. package/.agent-src/commands/roadmap/process-phase.md +1 -1
  71. package/.agent-src/commands/roadmap/process-step.md +1 -1
  72. package/.agent-src/commands/roadmap.md +1 -1
  73. package/.agent-src/commands/set-cost-profile.md +1 -1
  74. package/.agent-src/commands/skill/preview.md +3 -3
  75. package/.agent-src/commands/skill.md +1 -1
  76. package/.agent-src/commands/skills/discover.md +1 -1
  77. package/.agent-src/commands/skills.md +1 -1
  78. package/.agent-src/commands/sync-agent-settings.md +1 -1
  79. package/.agent-src/commands/sync-gitignore/fix.md +1 -1
  80. package/.agent-src/commands/sync-gitignore.md +1 -1
  81. package/.agent-src/commands/update-form-request-messages.md +1 -1
  82. package/.agent-src/skills/check-refs/SKILL.md +1 -1
  83. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
  84. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  85. package/.agent-src/skills/jira-integration/SKILL.md +1 -1
  86. package/.agent-src/skills/markitdown/SKILL.md +1 -1
  87. package/.agent-src/skills/prediction-pool-optimizer/SKILL.md +195 -77
  88. package/.agent-src/skills/prediction-pool-optimizer/evals/triggers.json +3 -1
  89. package/.agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +111 -16
  90. package/.agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +109 -0
  91. package/.agent-src/skills/rtk-output-filtering/SKILL.md +1 -1
  92. package/.agent-src/skills/script-writing/SKILL.md +1 -1
  93. package/.agent-src/skills/token-optimizer/SKILL.md +1 -1
  94. package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  95. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  96. package/.agent-src/templates/scripts/work_engine/_lib/agent_settings.py +52 -5
  97. package/.claude-plugin/marketplace.json +370 -366
  98. package/CHANGELOG.md +60 -0
  99. package/README.md +2 -2
  100. package/config/discovery/session-profiles.yml +37 -0
  101. package/dist/discovery/deprecation-report.md +1 -1
  102. package/dist/discovery/discovery-manifest.json +183 -95
  103. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  104. package/dist/discovery/discovery-manifest.summary.md +3 -3
  105. package/dist/discovery/orphan-report.md +1 -1
  106. package/dist/discovery/packs.json +9 -5
  107. package/dist/discovery/trust-report.md +2 -2
  108. package/dist/discovery/workspaces.json +8 -4
  109. package/dist/mcp/registry-manifest.json +3 -3
  110. package/docs/architecture.md +1 -1
  111. package/docs/catalog.md +7 -3
  112. package/docs/contracts/command-clusters.md +2 -0
  113. package/docs/contracts/session-profile-overlay.md +120 -0
  114. package/docs/customization.md +26 -0
  115. package/docs/decisions/ADR-010-profile-pack-preset-boundary.md +36 -0
  116. package/docs/decisions/ADR-038-canonical-settings-path.md +66 -0
  117. package/docs/decisions/ADR-039-claude-skills-untracked.md +139 -0
  118. package/docs/decisions/INDEX.md +2 -0
  119. package/docs/development.md +12 -0
  120. package/docs/getting-started.md +1 -1
  121. package/docs/guidelines/agent-infra/layered-settings.md +8 -2
  122. package/docs/skills-catalog.md +5 -1
  123. package/llms.txt +4 -0
  124. package/package.json +1 -1
  125. package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
  126. package/scripts/_cli/cmd_doctor.py +3 -2
  127. package/scripts/_cli/cmd_versions.py +2 -2
  128. package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
  129. package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
  130. package/scripts/_lib/agent_settings.py +52 -5
  131. package/scripts/_lib/agent_src.py +30 -0
  132. package/scripts/ai_council/session.py +5 -1
  133. package/scripts/audit_command_surface.py +7 -1
  134. package/scripts/audit_initial_context.py +10 -2
  135. package/scripts/check_gate_paths.py +117 -0
  136. package/scripts/check_references.py +51 -2
  137. package/scripts/check_test_coverage_diff.py +180 -0
  138. package/scripts/compile_router.py +5 -1
  139. package/scripts/condense.py +79 -2
  140. package/scripts/config/session_profiles.py +492 -0
  141. package/scripts/council_cli.py +5 -1
  142. package/scripts/hook_manifest.yaml +15 -7
  143. package/scripts/hooks/dispatch_hook.py +8 -0
  144. package/scripts/install-hooks.sh +2 -1
  145. package/scripts/install.py +76 -5
  146. package/scripts/inventory_abstraction_budget.py +6 -1
  147. package/scripts/lint_agents_md.py +11 -4
  148. package/scripts/lint_hook_concern_budget.py +5 -1
  149. package/scripts/lint_marketplace.py +18 -7
  150. package/scripts/lint_roadmap_ci_steps.py +5 -1
  151. package/scripts/lint_roadmap_complexity.py +5 -1
  152. package/scripts/mcp_server/prompts.py +5 -1
  153. package/scripts/prediction-pool/pool_winsim.py +236 -0
  154. package/scripts/prediction-pool/score_ev.py +188 -0
  155. package/scripts/profile_staleness_hook.py +69 -0
  156. package/scripts/roadmap_progress_hook.py +56 -6
  157. package/scripts/smoke_quickstart.py +3 -2
  158. package/scripts/sync_agent_settings.py +8 -3
  159. package/scripts/validate_agent_settings.py +5 -1
  160. package/scripts/validate_decision_engine.py +5 -1
  161. package/scripts/measure_roadmap_trajectory.py +0 -112
  162. package/scripts/verify_roadmap_closure.py +0 -327
@@ -127,6 +127,18 @@ task dev:link # Symlink this repo as the global @event4u/agent-
127
127
  task dev:unlink # Remove the global symlink
128
128
  ```
129
129
 
130
+ **Switch the global install between dev and release** — one-shot toggles
131
+ that flip BOTH the `agent-config` bin on PATH and the user-scope content:
132
+
133
+ ```bash
134
+ task install:use-dev # global = THIS working tree (npm link + dev-build content)
135
+ task install:use-release # global = latest npm release (npm i -g @latest + release content)
136
+ ```
137
+
138
+ Run `install:use-dev` to test the working tree as the live global install,
139
+ then `install:use-release` to switch back to the published version. They are
140
+ symmetric — whichever you run last is the active global `agent-config`.
141
+
130
142
  **Typical flow:**
131
143
 
132
144
  1. In this repo: `task dev:link` — once. The `agent-config` bin on PATH
@@ -169,7 +169,7 @@ Your agent now understands slash commands:
169
169
  | `/quality-fix` | Run and fix all quality checks |
170
170
  | `/chat-history` | Inspect the persistent chat-history log (read-only `show`) |
171
171
 
172
- → [Browse all 146 active commands](../.agent-src/commands/)
172
+ → [Browse all 150 active commands](../.agent-src/commands/)
173
173
 
174
174
  ---
175
175
 
@@ -19,7 +19,13 @@ on user request.
19
19
  |---|---|---|---|---|
20
20
  | `.agent-project-settings.yml` | **committed** | team / repo | lead maintainer | `project.stack`, `quality.php.tools`, `memory.dogfood` |
21
21
  | `~/.event4u/agent-config/agent-settings.yml` | **n/a** (outside repo) | individual developer · cross-project | individual | `name`, `ide`, `rule_loading_tier`, `personal.bot_icon`, `personal.autonomy`, `telegraph.speak_scope` (legacy `~/.config/agent-config/agent-settings.yml` read as fallback) |
22
- | `.agent-settings.yml` | **gitignored** | individual developer · this project | individual | `personal.ide`, `personal.user_name`, `subagents.max_parallel`, `onboarding.onboarded` |
22
+ | `agents/settings/.agent-settings.yml` | **gitignored** | individual developer · this project | individual | `personal.ide`, `personal.user_name`, `subagents.max_parallel`, `onboarding.onboarded` |
23
+
24
+ > **Canonical location (ADR-038):** the developer file lives in the settings
25
+ > layer at `agents/settings/.agent-settings.yml` (alongside
26
+ > `.agent-settings.local.yml`, `contexts/`, `policies/`). A repo-root
27
+ > `.agent-settings.yml` is read as a **back-compat fallback** and is migrated
28
+ > into the canonical location by `install` on the next run.
23
29
 
24
30
  All three are YAML. Schemas:
25
31
 
@@ -36,7 +42,7 @@ Lowest priority → highest priority:
36
42
  1. Package defaults (shipped by event4u/agent-config)
37
43
  2. ~/.event4u/agent-config/agent-settings.yml (user-global · whitelist-filtered · legacy ~/.config/agent-config/ read as fallback)
38
44
  3. .agent-project-settings.yml (team file, committed)
39
- 4. .agent-settings.yml (developer file, gitignored)
45
+ 4. agents/settings/.agent-settings.yml (developer file, gitignored; legacy repo-root .agent-settings.yml read as fallback — ADR-038)
40
46
  ```
41
47
 
42
48
  Keys from higher layers win unless a lower layer marks them
@@ -1,6 +1,6 @@
1
1
  # Skills Catalog
2
2
 
3
- All **219 skills** available in this package, in alphabetical order.
3
+ All **223 skills** available in this package, in alphabetical order.
4
4
  Click a skill name to open its SKILL.md and read the full guidance.
5
5
 
6
6
  > **Regenerate:** `python3 scripts/generate_catalog.py`
@@ -89,6 +89,8 @@ Click a skill name to open its SKILL.md and read the full guidance.
89
89
  | [`gtm-launch`](../.agent-src/skills/gtm-launch/SKILL.md) | Use when sequencing a launch — alpha / beta / GA waves, audience-by-wave logic, narrative beats per wave, engineering-readiness gates. Triggers on 'plan the launch', 'sequence GA'. |
90
90
  | [`guideline-writing`](../.agent-src/skills/guideline-writing/SKILL.md) | Use when creating or editing a guideline in docs/guidelines/ — reference material cited by skills, no auto-triggers — even when the user just says 'write up our naming conventions'. |
91
91
  | [`hiring-loop-design`](../.agent-src/skills/hiring-loop-design/SKILL.md) | Use when shaping an engineering hiring loop — stages, take-home vs live, calibration, bar-raiser, signal-vs-noise audit. Triggers on 'design our interview loop', 'audit our hiring bar'. |
92
+ | [`image-analyser`](../.agent-src/skills/image-analyser/SKILL.md) | Use to analyse a character image down to the smallest mole and diff against a canon — per-feature spec, OCR-reads tattoo text, flags drift. Triggers 'analyse this image', 'match the canon'. |
93
+ | [`image-creator`](../.agent-src/skills/image-creator/SKILL.md) | Use to generate a character image to spec — max-fidelity reproducible prompt from a Canon Spec, anchors-first, provider/governance-gated. Triggers 'generate this character', 'render to spec'. |
92
94
  | [`incident-commander`](../.agent-src/skills/incident-commander/SKILL.md) | Use during or right after an incident — frames severity, sets comms cadence, drafts the post-mortem skeleton — even when the user just says 'production is down' or 'wir haben einen Vorfall'. |
93
95
  | [`jira-integration`](../.agent-src/skills/jira-integration/SKILL.md) | Use when the user says "check Jira", "create ticket", "update issue", or needs JQL queries, ticket transitions, or branch-to-ticket linking. |
94
96
  | [`jobs-events`](../.agent-src/skills/jobs-events/SKILL.md) | Use when creating Laravel jobs, queued workflows, events, or listeners. Covers clear responsibilities, safe serialization, and retry/failure handling. |
@@ -152,6 +154,7 @@ Click a skill name to open its SKILL.md and read the full guidance.
152
154
  | [`playwright-testing`](../.agent-src/skills/playwright-testing/SKILL.md) | Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns. |
153
155
  | [`po-discovery`](../.agent-src/skills/po-discovery/SKILL.md) | Use when shaping a fuzzy product ask into a refined backlog item — problem framing, user-story rewrite, AC tightening — even if the user just says 'help me write this ticket'. |
154
156
  | [`positioning-strategy`](../.agent-src/skills/positioning-strategy/SKILL.md) | Use when locking the market frame — category, segment, alternative, point-of-view — before messaging, launch, or pricing rides on it. Triggers on 'who are we for', 'opposable audit'. |
157
+ | [`prediction-pool-optimizer`](../.agent-src/skills/prediction-pool-optimizer/SKILL.md) | Optimize prediction-pool tips (kicktipp etc.): rules + multi-book consensus odds → expected-points-max answer for every question, scores AND bonus. Triggers 'optimize my pool tips', 'predict'. |
155
158
  | [`privacy-review`](../.agent-src/skills/privacy-review/SKILL.md) | Use when reviewing data flows, support macros, refund templates for GDPR/CCPA/HIPAA fit — regime, consent, PII redaction (email, order-id), breach triage. Triggers 'is this GDPR-safe', 'PII redact'. |
156
159
  | [`project-analysis-core`](../.agent-src/skills/project-analysis-core/SKILL.md) | Raw discovery primitives — project discovery, version resolution, docs loading, architecture mapping, execution flow. Called by `universal-project-analysis`. Single-pass scan → `project-analyzer`. |
157
160
  | [`project-analysis-hypothesis-driven`](../.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md) | Use when a bug has multiple plausible causes across layers — competing hypotheses, validation loops, evidence-based conclusions — even when the user just says 'why is this happening?'. |
@@ -199,6 +202,7 @@ Click a skill name to open its SKILL.md and read the full guidance.
199
202
  | [`skill-management`](../.agent-src/skills/skill-management/SKILL.md) | Use when condensing, decondenseing, refactoring, or improving existing skills. Covers the full skill lifecycle from verbose → sharp → maintained. |
200
203
  | [`skill-reviewer`](../.agent-src/skills/skill-reviewer/SKILL.md) | Use when reviewing, auditing, or optimizing skills — validates against the 7 Skill Killers checklist and produces fix recommendations. |
201
204
  | [`skill-writing`](../.agent-src/skills/skill-writing/SKILL.md) | Use when deciding 'should this be a skill or a rule?', creating/improving/reviewing agent skills, SKILL.md frontmatter, or procedure sections — even without saying 'skill-writing'. |
205
+ | [`song-to-script`](../.agent-src/skills/song-to-script/SKILL.md) | Turn an audio track into a timed `## Scene N` script: song sections → per-scene durations, auto mode adds mood + lip-sync lines. Triggers 'music video', 'from the song', 'cut to the beat'. |
202
206
  | [`sql-writing`](../.agent-src/skills/sql-writing/SKILL.md) | Use when writing raw SQL — MariaDB/MySQL syntax, parameterization, raw migrations, seeders with `DB::statement` — even when the user just pastes a query and asks 'why is this slow' without naming SQL. |
203
207
  | [`stakeholder-tradeoff`](../.agent-src/skills/stakeholder-tradeoff/SKILL.md) | Use when stakeholders pull a decision in different directions — frames each lens, builds a trade-off matrix, surfaces the cost of every choice — even if the user just says 'PO and ops disagree'. |
204
208
  | [`subagent-orchestration`](../.agent-src/skills/subagent-orchestration/SKILL.md) | Use when orchestrating implementer/judge subagents — seven modes (do-and-judge ±two-stage, do-in-steps/parallel/worktrees, do-competitively, judge-with-debate) — models from .agent-settings.yml. |
package/llms.txt CHANGED
@@ -87,6 +87,8 @@ grafana: Use when working with Grafana — dashboards, Loki LogQL queries, alert
87
87
  gtm-launch: Use when sequencing a launch — alpha / beta / GA waves, audience-by-wave logic, narrative beats per wave, engineering-readiness gates. Triggers on 'plan the launch', 'sequence GA'.
88
88
  guideline-writing: Use when creating or editing a guideline in docs/guidelines/ — reference material cited by skills, no auto-triggers — even when the user just says 'write up our naming conventions'.
89
89
  hiring-loop-design: Use when shaping an engineering hiring loop — stages, take-home vs live, calibration, bar-raiser, signal-vs-noise audit. Triggers on 'design our interview loop', 'audit our hiring bar'.
90
+ image-analyser: Use to analyse a character image down to the smallest mole and diff against a canon — per-feature spec, OCR-reads tattoo text, flags drift. Triggers 'analyse this image', 'match the canon'.
91
+ image-creator: Use to generate a character image to spec — max-fidelity reproducible prompt from a Canon Spec, anchors-first, provider/governance-gated. Triggers 'generate this character', 'render to spec'.
90
92
  incident-commander: Use during or right after an incident — frames severity, sets comms cadence, drafts the post-mortem skeleton — even when the user just says 'production is down' or 'wir haben einen Vorfall'.
91
93
  jira-integration: Use when the user says "check Jira", "create ticket", "update issue", or needs JQL queries, ticket transitions, or branch-to-ticket linking.
92
94
  jobs-events: Use when creating Laravel jobs, queued workflows, events, or listeners. Covers clear responsibilities, safe serialization, and retry/failure handling.
@@ -150,6 +152,7 @@ playwright-architect: Use when shaping a Playwright suite — locator strategy,
150
152
  playwright-testing: Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns.
151
153
  po-discovery: Use when shaping a fuzzy product ask into a refined backlog item — problem framing, user-story rewrite, AC tightening — even if the user just says 'help me write this ticket'.
152
154
  positioning-strategy: Use when locking the market frame — category, segment, alternative, point-of-view — before messaging, launch, or pricing rides on it. Triggers on 'who are we for', 'opposable audit'.
155
+ prediction-pool-optimizer: Optimize prediction-pool tips (kicktipp etc.): rules + multi-book consensus odds → expected-points-max answer for every question, scores AND bonus. Triggers 'optimize my pool tips', 'predict'.
153
156
  privacy-review: Use when reviewing data flows, support macros, refund templates for GDPR/CCPA/HIPAA fit — regime, consent, PII redaction (email, order-id), breach triage. Triggers 'is this GDPR-safe', 'PII redact'.
154
157
  project-analysis-core: Raw discovery primitives — project discovery, version resolution, docs loading, architecture mapping, execution flow. Called by `universal-project-analysis`. Single-pass scan → `project-analyzer`.
155
158
  project-analysis-hypothesis-driven: Use when a bug has multiple plausible causes across layers — competing hypotheses, validation loops, evidence-based conclusions — even when the user just says 'why is this happening?'.
@@ -197,6 +200,7 @@ skill-improvement-pipeline: ONLY when user explicitly requests: run the skill im
197
200
  skill-management: Use when condensing, decondenseing, refactoring, or improving existing skills. Covers the full skill lifecycle from verbose → sharp → maintained.
198
201
  skill-reviewer: Use when reviewing, auditing, or optimizing skills — validates against the 7 Skill Killers checklist and produces fix recommendations.
199
202
  skill-writing: Use when deciding 'should this be a skill or a rule?', creating/improving/reviewing agent skills, SKILL.md frontmatter, or procedure sections — even without saying 'skill-writing'.
203
+ song-to-script: Turn an audio track into a timed `## Scene N` script: song sections → per-scene durations, auto mode adds mood + lip-sync lines. Triggers 'music video', 'from the song', 'cut to the beat'.
200
204
  sql-writing: Use when writing raw SQL — MariaDB/MySQL syntax, parameterization, raw migrations, seeders with `DB::statement` — even when the user just pastes a query and asks 'why is this slow' without naming SQL.
201
205
  stakeholder-tradeoff: Use when stakeholders pull a decision in different directions — frames each lens, builds a trade-off matrix, surfaces the cost of every choice — even if the user just says 'PO and ops disagree'.
202
206
  subagent-orchestration: Use when orchestrating implementer/judge subagents — seven modes (do-and-judge ±two-stage, do-in-steps/parallel/worktrees, do-competitively, judge-with-debate) — models from .agent-settings.yml.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event4u/agent-config",
3
- "version": "5.7.0",
3
+ "version": "5.8.0",
4
4
  "description": "Universal AI Agent OS \u2014 audited skills, governance rules, commands, and templates for AI coding tools (Claude Code, Cursor, Windsurf, Copilot).",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -55,6 +55,7 @@ from scripts._lib.agent_settings import (
55
55
  ROOT_OVERRIDE_ENV,
56
56
  ProjectRootError,
57
57
  find_project_root_with_trace,
58
+ project_settings_path,
58
59
  resolve_project_root,
59
60
  )
60
61
 
@@ -131,7 +132,7 @@ def _settings_layer_chain(project_root: Path) -> list[str]:
131
132
  user_global = user_global_paths.resolve_with_fallback("agent-settings.yml")
132
133
  if user_global is not None and user_global.is_file():
133
134
  layers.append(str(user_global))
134
- project_settings = project_root / ".agent-settings.yml"
135
+ project_settings = project_settings_path(project_root)
135
136
  if project_settings.is_file():
136
137
  layers.append(str(project_settings))
137
138
  return layers
@@ -778,7 +779,7 @@ def _check_tier_usage_readiness(project_root: Path) -> dict[str, Any]:
778
779
 
779
780
  Contract: ``docs/contracts/command-clusters.md`` § tier-usage signal.
780
781
  """
781
- settings_file = project_root / ".agent-settings.yml"
782
+ settings_file = project_settings_path(project_root)
782
783
  log_path = project_root / ".agent-tier-usage.jsonl"
783
784
  enabled = False
784
785
  if settings_file.is_file():
@@ -18,7 +18,7 @@ import subprocess
18
18
  import sys
19
19
  from pathlib import Path
20
20
 
21
- from scripts._lib.agent_settings import resolve_project_root
21
+ from scripts._lib.agent_settings import project_settings_path, resolve_project_root
22
22
 
23
23
  PACKAGE_NAME = "@event4u/agent-config"
24
24
 
@@ -51,7 +51,7 @@ def _local_package_version() -> str:
51
51
 
52
52
  def _pinned_version() -> str:
53
53
  """Return the ``agent_config_version`` pin from ``.agent-settings.yml``."""
54
- settings = _project_root() / ".agent-settings.yml"
54
+ settings = project_settings_path(_project_root())
55
55
  if not settings.exists():
56
56
  return ""
57
57
  try:
@@ -76,6 +76,45 @@ def _local_settings_path(project_root: Path) -> Path:
76
76
  return project_root.joinpath(*LOCAL_PROJECT_SUBDIR, LOCAL_PROJECT_FILE)
77
77
 
78
78
 
79
+ def _canonical_settings_path(project_root: Path) -> Path:
80
+ """Canonical project settings file: ``<root>/agents/settings/.agent-settings.yml``.
81
+
82
+ The project settings file lives in the project's settings layer
83
+ (``agents/settings/``, alongside ``contexts/`` and ``policies/`` and
84
+ the ``.agent-settings.local.yml`` override), NOT at the repo root.
85
+ The repo-root ``.agent-settings.yml`` is a legacy location read only
86
+ as a back-compat fallback (see :func:`project_settings_path`).
87
+ """
88
+ return project_root.joinpath(*LOCAL_PROJECT_SUBDIR, DEFAULT_PROJECT_FILE)
89
+
90
+
91
+ def project_settings_path(project_root: Path) -> Path:
92
+ """Resolve the project settings file for **reading**.
93
+
94
+ Returns the canonical ``agents/settings/.agent-settings.yml`` when it
95
+ exists; otherwise the legacy repo-root ``.agent-settings.yml`` when
96
+ that exists (back-compat for installs predating the relocation);
97
+ otherwise the canonical path (so the caller still names the right
98
+ target on a fresh repo). Existence-checked, never writes.
99
+ """
100
+ canonical = _canonical_settings_path(project_root)
101
+ if canonical.exists():
102
+ return canonical
103
+ legacy = project_root / DEFAULT_PROJECT_FILE
104
+ if legacy.exists():
105
+ return legacy
106
+ return canonical
107
+
108
+
109
+ def canonical_settings_write_path(project_root: Path) -> Path:
110
+ """Always the canonical **write** target: ``agents/settings/.agent-settings.yml``.
111
+
112
+ Writers (install, sync, migrate) target this unconditionally; the
113
+ legacy root file is migrated into it, never written afresh.
114
+ """
115
+ return _canonical_settings_path(project_root)
116
+
117
+
79
118
  DEFAULT_TEAM_FILE = ".agent-project-settings.yml"
80
119
  USER_GLOBAL_FILENAME = "agent-settings.yml"
81
120
 
@@ -431,12 +470,14 @@ def _resolve_cascade_paths(
431
470
  """
432
471
  if cwd is None:
433
472
  legacy = Path(project_path) if project_path else Path(DEFAULT_PROJECT_FILE)
434
- return [legacy, _local_settings_path(legacy.parent)]
473
+ return [legacy, _canonical_settings_path(legacy.parent),
474
+ _local_settings_path(legacy.parent)]
435
475
 
436
476
  root = find_project_root(cwd)
437
477
  if root is None:
438
478
  legacy = Path(project_path) if project_path else Path(DEFAULT_PROJECT_FILE)
439
- return [legacy, _local_settings_path(legacy.parent)]
479
+ return [legacy, _canonical_settings_path(legacy.parent),
480
+ _local_settings_path(legacy.parent)]
440
481
 
441
482
  cwd_resolved = cwd.resolve()
442
483
  # Build the chain root → … → cwd (shallowest first, deepest last).
@@ -451,9 +492,15 @@ def _resolve_cascade_paths(
451
492
  break
452
493
  cursor = parent
453
494
  chain.reverse()
454
- # Committed cascade root → cwd, then the single project-level local override
455
- # under agents/settings/ as the deepest (winning) layer.
456
- return [d / DEFAULT_PROJECT_FILE for d in chain] + [_local_settings_path(root)]
495
+ # Legacy per-dir cascade root → cwd (repo-root .agent-settings.yml is the
496
+ # shallowest, back-compat), then the canonical project settings file under
497
+ # agents/settings/ (wins over the legacy root location), then the
498
+ # per-machine local override under agents/settings/ as the deepest (winning)
499
+ # layer.
500
+ return (
501
+ [d / DEFAULT_PROJECT_FILE for d in chain]
502
+ + [_canonical_settings_path(root), _local_settings_path(root)]
503
+ )
457
504
 
458
505
 
459
506
  def load_agent_settings(
@@ -30,6 +30,7 @@ from typing import Iterator
30
30
  ROOT = Path(__file__).resolve().parents[2]
31
31
  LEGACY_SRC = ROOT / ".agent-src.uncondensed"
32
32
  PACKAGES = ROOT / "packages"
33
+ PACKAGE_CORE = PACKAGES / "core"
33
34
 
34
35
  # Repo-relative POSIX path prefixes that anchor an artefact source tree.
35
36
  # Order: legacy first (kept until the move lands), then packages/*. Each
@@ -155,3 +156,32 @@ def strip_source_prefix(rel: str) -> str | None:
155
156
  def is_artefact_path(rel: str) -> bool:
156
157
  """``True`` if a repo-relative POSIX path sits under any source root."""
157
158
  return strip_source_prefix(rel) is not None
159
+
160
+
161
+ def resolve_package_core_path(relative_target: str) -> Path:
162
+ """Return the canonical ``packages/core/<relative_target>`` path.
163
+
164
+ The single resolution point for every gate that enforces something
165
+ against a fixed ``packages/core/`` target. A future move of the
166
+ ``packages/core/`` tree updates :data:`PACKAGE_CORE` here — one
167
+ resolver — instead of N hard-coded ``REPO_ROOT / "packages" / "core"``
168
+ constants scattered across gate scripts (the ``aab5755`` silent-no-op
169
+ class this eliminates).
170
+
171
+ Pure resolver: deterministic, **no filesystem I/O**. ``agent_src`` is
172
+ imported by scanners that must stay usable in the legacy-only and
173
+ pack-only layouts (see :func:`artefact_roots`), so this MUST NOT
174
+ assert existence at import or call time — a packages/core existence
175
+ check here would break those layouts. Callers that need existence
176
+ check it themselves; ``scripts/check_gate_paths.py`` is the single
177
+ gate that asserts the enforced targets resolve under ``packages/core/``.
178
+
179
+ Examples:
180
+ ``resolve_package_core_path(".agent-src.uncondensed")``
181
+ → ``<repo>/packages/core/.agent-src.uncondensed``
182
+ ``resolve_package_core_path(".agent-src.uncondensed/commands")``
183
+ → ``<repo>/packages/core/.agent-src.uncondensed/commands``
184
+ ``resolve_package_core_path("")`` → ``<repo>/packages/core``
185
+ """
186
+ rel = relative_target.replace("\\", "/").lstrip("/")
187
+ return PACKAGE_CORE / rel if rel else PACKAGE_CORE
@@ -28,6 +28,10 @@ import shutil
28
28
  import sys
29
29
  from dataclasses import dataclass, field
30
30
  from pathlib import Path
31
+ try: # invocation-agnostic import (repo-root-on-path vs scripts-on-path)
32
+ from scripts._lib.agent_settings import project_settings_path
33
+ except ModuleNotFoundError: # pragma: no cover
34
+ from _lib.agent_settings import project_settings_path
31
35
  from typing import Iterable
32
36
 
33
37
  from scripts.ai_council.clients import CouncilResponse
@@ -37,7 +41,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2]
37
41
  SESSIONS_DIR = REPO_ROOT / "agents" / "runtime" / "council" / "sessions"
38
42
  QUESTIONS_DIR = REPO_ROOT / "agents" / "runtime" / "council" / "questions"
39
43
  RESPONSES_DIR = REPO_ROOT / "agents" / "runtime" / "council" / "responses"
40
- SETTINGS_FILE = REPO_ROOT / ".agent-settings.yml"
44
+ SETTINGS_FILE = project_settings_path(REPO_ROOT)
41
45
 
42
46
  # Default retention for all council artefacts (questions, responses,
43
47
  # sessions). Overridden by `ai_council.session_retention_days`
@@ -37,12 +37,18 @@ from pathlib import Path
37
37
  from typing import List
38
38
 
39
39
  REPO_ROOT = Path(__file__).resolve().parent.parent
40
+ sys.path.insert(0, str(REPO_ROOT / "scripts"))
41
+ from _lib.agent_src import resolve_package_core_path # noqa: E402
42
+
40
43
  # Pre-monorepo: REPO_ROOT/.agent-src.uncondensed/commands. Post-move (ADR-017)
41
44
  # the core command surface lives under packages/core/.agent-src.uncondensed.
42
45
  # Fall back to the legacy path only if the packages layout is absent.
43
- _CORE_COMMANDS = REPO_ROOT / "packages" / "core" / ".agent-src.uncondensed" / "commands"
46
+ _CORE_COMMANDS = resolve_package_core_path(".agent-src.uncondensed/commands")
44
47
  _LEGACY_COMMANDS = REPO_ROOT / ".agent-src.uncondensed" / "commands"
45
48
  DEFAULT_ROOT = _CORE_COMMANDS if _CORE_COMMANDS.is_dir() else _LEGACY_COMMANDS
49
+ # Enforced packages/core target — read by scripts/check_gate_paths.py so a
50
+ # future move that desyncs this path fails CI instead of silently no-opping.
51
+ GATE_CORE_PATHS = (_CORE_COMMANDS,)
46
52
  REPORT_DIR = REPO_ROOT / "agents" / "reports"
47
53
  OUT_JSON = REPORT_DIR / "command-surface.json"
48
54
  OUT_MD = REPORT_DIR / "command-surface.md"
@@ -35,6 +35,13 @@ from pathlib import Path
35
35
  REPO_ROOT = Path(__file__).resolve().parent.parent
36
36
  sys.path.insert(0, str(REPO_ROOT / "scripts"))
37
37
  from _lib import token_count # noqa: E402
38
+ from _lib.agent_src import resolve_package_core_path # noqa: E402
39
+
40
+ _CORE_SRC = resolve_package_core_path(".agent-src.uncondensed")
41
+ # Enforced packages/core targets — the skills + commands dirs the
42
+ # description-catalog globs scan. Read by scripts/check_gate_paths.py so a
43
+ # future move that desyncs them fails CI instead of silently no-opping.
44
+ GATE_CORE_PATHS = (_CORE_SRC / "skills", _CORE_SRC / "commands")
38
45
 
39
46
  try:
40
47
  import yaml
@@ -111,10 +118,11 @@ def _catalog(glob_pat: str) -> dict:
111
118
 
112
119
  def description_catalog() -> dict:
113
120
  """0B.4 — description-catalog cost (eager progressive-disclosure surface)."""
121
+ core_rel = _CORE_SRC.relative_to(REPO_ROOT).as_posix()
114
122
  return {
115
123
  "skills_projected": _catalog(".claude/skills/*/SKILL.md"),
116
- "skills_core_source": _catalog("packages/core/.agent-src.uncondensed/skills/*/SKILL.md"),
117
- "commands_core_source": _catalog("packages/core/.agent-src.uncondensed/commands/**/*.md"),
124
+ "skills_core_source": _catalog(f"{core_rel}/skills/*/SKILL.md"),
125
+ "commands_core_source": _catalog(f"{core_rel}/commands/**/*.md"),
118
126
  }
119
127
 
120
128
 
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python3
2
+ """Gate path-integrity check (R2 of road-to-test-and-gate-integrity).
3
+
4
+ Asserts that every security/quality gate which enforces something against
5
+ a fixed ``packages/core/`` target still resolves that target on disk. A
6
+ ``packages/core/`` move that desyncs a gate's hard-coded path fails CI here
7
+ instead of silently no-opping (the ``aab5755`` class: the Iron-Law SHA gate
8
+ pointed at a stale path and enforced nothing while CI stayed green).
9
+
10
+ Design (AI council, claude-sonnet-4-5 + gpt-4o, 2026-06-02):
11
+
12
+ - The check reads each gate's ACTUAL enforced paths via its module-level
13
+ ``GATE_CORE_PATHS`` attribute — it does NOT re-declare a copy of the path
14
+ strings. A hand-maintained path registry would reintroduce the very
15
+ desync risk this guards against, one layer down.
16
+ - Scope is strictly the single-root hard-coders. Multi-root gates that
17
+ resolve via ``artefact_roots()`` (e.g. ``iron_law_sha``) are excluded:
18
+ asserting a single ``packages/core/`` path for them would false-pass on a
19
+ legacy layout or false-fail on a pack-only layout.
20
+
21
+ The input set is this gate list (no separate config file).
22
+
23
+ Usage:
24
+ python3 scripts/check_gate_paths.py
25
+ Exit codes: 0 = all enforced targets resolve under packages/core/ ·
26
+ 1 = at least one missing / out-of-tree target · 2 = a gate failed to import.
27
+ """
28
+ from __future__ import annotations
29
+
30
+ import importlib
31
+ import sys
32
+ from pathlib import Path
33
+
34
+ REPO_ROOT = Path(__file__).resolve().parent.parent
35
+ sys.path.insert(0, str(REPO_ROOT / "scripts"))
36
+ from _lib.agent_src import resolve_package_core_path # noqa: E402
37
+
38
+ PACKAGE_CORE = resolve_package_core_path("")
39
+
40
+ # Single-root gates that enforce against a fixed packages/core/ target and
41
+ # expose it via a module-level GATE_CORE_PATHS tuple. Adding a gate here is
42
+ # the only manual step; its paths are read from the gate, never copied.
43
+ GATES: tuple[str, ...] = (
44
+ "inventory_abstraction_budget",
45
+ "audit_command_surface",
46
+ "lint_agents_md",
47
+ "audit_initial_context",
48
+ )
49
+
50
+
51
+ def _is_under_core(p: Path) -> bool:
52
+ try:
53
+ p.resolve().relative_to(PACKAGE_CORE.resolve())
54
+ return True
55
+ except ValueError:
56
+ return False
57
+
58
+
59
+ def collect_gate_paths(gate_modules: tuple[str, ...]) -> dict[str, list[Path]]:
60
+ """Import each gate and read its declared ``GATE_CORE_PATHS``.
61
+
62
+ Raises ``ImportError`` (surfaced as exit 2 by ``main``) if a gate cannot
63
+ be imported — a gate whose path logic broke at import time is itself a
64
+ failure this check should not swallow.
65
+ """
66
+ out: dict[str, list[Path]] = {}
67
+ for name in gate_modules:
68
+ mod = importlib.import_module(name)
69
+ paths = getattr(mod, "GATE_CORE_PATHS", None)
70
+ if not paths:
71
+ raise AttributeError(
72
+ f"{name} has no non-empty GATE_CORE_PATHS — gate cannot be "
73
+ f"checked. Declare the packages/core targets it enforces."
74
+ )
75
+ out[name] = [Path(p) for p in paths]
76
+ return out
77
+
78
+
79
+ def check_paths(named: dict[str, list[Path]]) -> list[tuple[str, str, Path]]:
80
+ """Return ``(gate, reason, path)`` for every target that fails.
81
+
82
+ Pure (no import side effects) so tests can drive it with fixtures.
83
+ A target fails when it does not resolve under ``packages/core/`` or
84
+ does not exist on disk.
85
+ """
86
+ failures: list[tuple[str, str, Path]] = []
87
+ for gate, paths in named.items():
88
+ for p in paths:
89
+ if not _is_under_core(p):
90
+ failures.append((gate, "not under packages/core/", p))
91
+ elif not p.exists():
92
+ failures.append((gate, "target does not exist", p))
93
+ return failures
94
+
95
+
96
+ def main() -> int:
97
+ try:
98
+ named = collect_gate_paths(GATES)
99
+ except (ImportError, AttributeError) as exc:
100
+ print(f"❌ check-gate-paths: {exc}", file=sys.stderr)
101
+ return 2
102
+ failures = check_paths(named)
103
+ if failures:
104
+ print("❌ check-gate-paths: gate target(s) do not resolve under packages/core/:")
105
+ for gate, reason, path in failures:
106
+ print(f" {gate}: {reason} → {path}")
107
+ print("\n A packages/core/ move likely desynced a gate. Fix the gate's")
108
+ print(" GATE_CORE_PATHS (built via resolve_package_core_path) or the move.")
109
+ return 1
110
+ total = sum(len(v) for v in named.values())
111
+ print(f"✅ check-gate-paths: {total} enforced target(s) across "
112
+ f"{len(named)} gate(s) resolve under packages/core/.")
113
+ return 0
114
+
115
+
116
+ if __name__ == "__main__":
117
+ raise SystemExit(main())
@@ -133,6 +133,53 @@ EXAMPLE_PATH_PATTERNS = [
133
133
  ]
134
134
 
135
135
 
136
+ @dataclass(frozen=True)
137
+ class AllowlistPattern:
138
+ """A token-class allowlist entry. `reason` is mandatory and auditable."""
139
+ pattern: "re.Pattern[str]"
140
+ reason: str
141
+
142
+
143
+ # Content-class allowlist for known NON-reference token shapes.
144
+ #
145
+ # The skill/rule prose patterns (`X` skill / `X` rule) occasionally match
146
+ # a backtick token that is not an artifact id — an execution-type enum
147
+ # value, a pack identifier, or a bare meta-qualifier keyword. Historically
148
+ # each such false positive was dodged by *rewording the prose per file*
149
+ # (e.g. dc84ed01 "reword execution-type mentions to dodge check-refs
150
+ # false positive", bd02ef0b "avoid check-refs false-positive on pack
151
+ # name"), a treadmill that distorts natural wording release after release.
152
+ # This layer matches the token *class* centrally instead, so the natural
153
+ # wording passes without per-file edits. It is distinct from:
154
+ # - SKIP_DIRS (path-level, whole-directory)
155
+ # - FILE_SKIP_MARKER (file-level opt-out)
156
+ # - LINE_IGNORE_MARKER (per-line opt-out)
157
+ # Every entry carries a mandatory `reason` so the allowlist stays
158
+ # auditable and a future reader can tell why a class is exempt.
159
+ ALLOWLIST_PATTERNS: List[AllowlistPattern] = [
160
+ AllowlistPattern(
161
+ re.compile(r"^(?:manual|assisted|automated)$"),
162
+ "execution-type enum value (runtime-safety frontmatter), e.g. a "
163
+ "`manual` skill — not a skill/rule id (dc84ed01)",
164
+ ),
165
+ AllowlistPattern(
166
+ re.compile(r"^pack-[\w-]+$"),
167
+ "pack / workspace identifier, e.g. `pack-ai-video` skills — not a "
168
+ "skill/rule id (bd02ef0b)",
169
+ ),
170
+ AllowlistPattern(
171
+ re.compile(r"^(?:skill|rule|command|guideline|persona|context|pack|workspace)$"),
172
+ "bare meta-qualifier keyword used in prose (the `command` vs "
173
+ "`skill` distinction, etc.) — not an artifact id",
174
+ ),
175
+ ]
176
+
177
+
178
+ def _is_allowlisted(name: str) -> bool:
179
+ """True when `name` matches a known non-reference token class."""
180
+ return any(entry.pattern.match(name) for entry in ALLOWLIST_PATTERNS)
181
+
182
+
136
183
  def collect_artifacts(root: Path) -> dict[str, set[str]]:
137
184
  """Build lookup sets for skills, rules, commands, guidelines, personas."""
138
185
  arts: dict[str, set[str]] = {
@@ -345,7 +392,8 @@ def check_file(filepath: Path, artifacts: dict[str, set[str]], root: Path) -> Li
345
392
  # Skill name references
346
393
  for m in SKILL_REF_PATTERN.finditer(line):
347
394
  name = m.group(1)
348
- if name not in artifacts["skills"] and name not in _SKIP_NAMES:
395
+ if name not in artifacts["skills"] and name not in _SKIP_NAMES \
396
+ and not _is_allowlisted(name):
349
397
  broken.append(BrokenRef(
350
398
  file=str(filepath), line=i, ref=name,
351
399
  ref_type="skill", severity="warning",
@@ -355,7 +403,8 @@ def check_file(filepath: Path, artifacts: dict[str, set[str]], root: Path) -> Li
355
403
  # Rule name references
356
404
  for m in RULE_REF_PATTERN.finditer(line):
357
405
  name = m.group(1)
358
- if name not in artifacts["rules"] and name not in _SKIP_NAMES:
406
+ if name not in artifacts["rules"] and name not in _SKIP_NAMES \
407
+ and not _is_allowlisted(name):
359
408
  broken.append(BrokenRef(
360
409
  file=str(filepath), line=i, ref=name,
361
410
  ref_type="rule", severity="warning",