@event4u/agent-config 5.7.0 → 5.9.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 (164) 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 +77 -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 +180 -16
  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_release_published.py +145 -0
  138. package/scripts/check_test_coverage_diff.py +180 -0
  139. package/scripts/compile_router.py +5 -1
  140. package/scripts/condense.py +79 -2
  141. package/scripts/config/session_profiles.py +492 -0
  142. package/scripts/council_cli.py +5 -1
  143. package/scripts/hook_manifest.yaml +15 -7
  144. package/scripts/hooks/dispatch_hook.py +8 -0
  145. package/scripts/install-hooks.sh +2 -1
  146. package/scripts/install.py +76 -5
  147. package/scripts/inventory_abstraction_budget.py +6 -1
  148. package/scripts/lint_agents_md.py +11 -4
  149. package/scripts/lint_hook_concern_budget.py +5 -1
  150. package/scripts/lint_marketplace.py +18 -7
  151. package/scripts/lint_roadmap_ci_steps.py +5 -1
  152. package/scripts/lint_roadmap_complexity.py +5 -1
  153. package/scripts/mcp_server/prompts.py +5 -1
  154. package/scripts/prediction-pool/pool_winsim.py +236 -0
  155. package/scripts/prediction-pool/score_ev.py +188 -0
  156. package/scripts/profile_staleness_hook.py +69 -0
  157. package/scripts/release.py +54 -31
  158. package/scripts/roadmap_progress_hook.py +56 -6
  159. package/scripts/smoke_quickstart.py +3 -2
  160. package/scripts/sync_agent_settings.py +8 -3
  161. package/scripts/validate_agent_settings.py +5 -1
  162. package/scripts/validate_decision_engine.py +5 -1
  163. package/scripts/measure_roadmap_trajectory.py +0 -112
  164. 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.9.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,
@@ -23,8 +23,16 @@ mcp-mode · mcp-beta-readiness · offline-readiness · python-runtime ·
23
23
  tier-usage-readiness · council-cli · unsupported-combos ·
24
24
  wizard-state.
25
25
  Each emits a structured ``{id, status, message, remedy}`` record with
26
- ``status`` ∈ ``ok`` / ``warn`` / ``fail`` (rendered ``✅`` / ``⚠️`` /
27
- ``❌``). ``--check <id>`` runs a single check.
26
+ ``status`` ∈ ``ok`` / ``warn`` / ``fail`` / ``skipped`` (rendered
27
+ ``✅`` / ``⚠️`` / ``❌`` / ``⏭️``). ``--check <id>`` runs a single check.
28
+
29
+ Checks are split by scope (:data:`GLOBAL_CHECK_IDS` vs
30
+ :data:`MANIFEST_REQUIRED_CHECK_IDS`) so an ADR-020 global-only consumer
31
+ (bridge marker present, no ``agents/installed-tools.lock``) gets a
32
+ green-capable report instead of a hard bail: the global checks run, the
33
+ manifest-required checks report ``skipped``, and ``bridge-drift`` returns
34
+ a scope-aware "drift not applicable" verdict. See :func:`main` for the
35
+ no-manifest branch and exit-code contract.
28
36
 
29
37
  Repair affordances: ``--repair wizard-state`` resets a malformed or
30
38
  orphaned ``state/wizard-state.json`` under the user-global root (the
@@ -55,6 +63,7 @@ from scripts._lib.agent_settings import (
55
63
  ROOT_OVERRIDE_ENV,
56
64
  ProjectRootError,
57
65
  find_project_root_with_trace,
66
+ project_settings_path,
58
67
  resolve_project_root,
59
68
  )
60
69
 
@@ -131,7 +140,7 @@ def _settings_layer_chain(project_root: Path) -> list[str]:
131
140
  user_global = user_global_paths.resolve_with_fallback("agent-settings.yml")
132
141
  if user_global is not None and user_global.is_file():
133
142
  layers.append(str(user_global))
134
- project_settings = project_root / ".agent-settings.yml"
143
+ project_settings = project_settings_path(project_root)
135
144
  if project_settings.is_file():
136
145
  layers.append(str(project_settings))
137
146
  return layers
@@ -454,6 +463,41 @@ CHECK_IDS = (
454
463
  "wizard-state",
455
464
  )
456
465
 
466
+ #: Checks that need only the project root (or no input at all) and run
467
+ #: regardless of whether a project lockfile exists. Under ADR-020
468
+ #: global-only (bridge marker present, no ``installed-tools.lock``) these
469
+ #: still produce a real verdict. ``scope`` lives here because
470
+ #: :func:`_check_scope` reads only ``project_root`` — the roadmap prose
471
+ #: that grouped it with the manifest checks predates this code reality
472
+ #: (AI council, claude-sonnet-4-5 + gpt-4o, design lens, 2026-06-02).
473
+ GLOBAL_CHECK_IDS: frozenset[str] = frozenset({
474
+ "scope",
475
+ "global-binary",
476
+ "mcp-mode",
477
+ "mcp-beta-readiness",
478
+ "offline-readiness",
479
+ "python-runtime",
480
+ "tier-usage-readiness",
481
+ "council-cli",
482
+ "wizard-state",
483
+ })
484
+
485
+ #: Checks that genuinely cannot run without the project manifest. Without
486
+ #: a lockfile they report ``skipped`` rather than a misleading verdict.
487
+ #: ``bridge-drift`` is deliberately **not** here: it is scope-aware —
488
+ #: a manifest-derived drift roll-up when the lockfile exists, and a
489
+ #: "drift not applicable (global-only consumer)" verdict when it does
490
+ #: not (computed in :func:`_check_bridge_drift_no_manifest`, keeping
491
+ #: :func:`_check_bridge_drift` a pure roll-up per the council's SRP point).
492
+ MANIFEST_REQUIRED_CHECK_IDS: frozenset[str] = frozenset({
493
+ "manifest-integrity",
494
+ "lockfile-freshness",
495
+ "unsupported-combos",
496
+ })
497
+
498
+ #: Project-root-relative path of the ADR-020 global-only consumer marker.
499
+ BRIDGE_MARKER_RELATIVE = "agents/.event4u-bridge.yml"
500
+
457
501
  #: Repair targets that ``--repair <id>`` accepts. Each id maps to a
458
502
  #: function in :func:`_run_repair` that resets the named artefact and
459
503
  #: returns an exit code. Additive set: introduce by adding a new id
@@ -475,7 +519,7 @@ MCP_BETA_GATES: tuple[tuple[str, str], ...] = (
475
519
 
476
520
  #: Visible status → glyph map. ``warn`` keeps a trailing space so the
477
521
  #: rendered output stays in a single visual column with the other glyphs.
478
- STATUS_SYMBOLS = {"ok": "✅", "warn": "⚠️ ", "fail": "❌"}
522
+ STATUS_SYMBOLS = {"ok": "✅", "warn": "⚠️ ", "fail": "❌", "skipped": "⏭️ "}
479
523
 
480
524
  #: Minimum Python interpreter the CLI targets. Bumped in lockstep with
481
525
  #: ``from __future__ import annotations`` + PEP-604 syntax usage.
@@ -778,7 +822,7 @@ def _check_tier_usage_readiness(project_root: Path) -> dict[str, Any]:
778
822
 
779
823
  Contract: ``docs/contracts/command-clusters.md`` § tier-usage signal.
780
824
  """
781
- settings_file = project_root / ".agent-settings.yml"
825
+ settings_file = project_settings_path(project_root)
782
826
  log_path = project_root / ".agent-tier-usage.jsonl"
783
827
  enabled = False
784
828
  if settings_file.is_file():
@@ -1158,6 +1202,131 @@ def _run_checks(
1158
1202
  return out
1159
1203
 
1160
1204
 
1205
+ def _skipped_manifest_check(check_id: str) -> dict[str, Any]:
1206
+ """A ``skipped`` verdict for a manifest-required check with no lockfile.
1207
+
1208
+ Explicit machine-readable record (not omitted, not ``null``) so the
1209
+ ``--json`` ``checks`` array keeps a stable shape for a global-only
1210
+ consumer — a council convergence point (2026-06-02).
1211
+ """
1212
+ return {
1213
+ "id": check_id, "status": "skipped",
1214
+ "message": "requires a project lockfile (agents/installed-tools.lock)",
1215
+ "remedy": "run `agent-config init` to create a project lockfile, "
1216
+ "then re-run this check",
1217
+ }
1218
+
1219
+
1220
+ def _check_bridge_drift_no_manifest(bridge_present: bool) -> dict[str, Any]:
1221
+ """Scope-aware ``bridge-drift`` verdict when no project manifest exists.
1222
+
1223
+ Kept out of :func:`_check_bridge_drift` (which stays a pure
1224
+ manifest-derived roll-up) per the council's single-responsibility
1225
+ point. A global-only consumer has no distributed tools to drift, so
1226
+ a bridge-present repo reports ``ok`` ("not applicable"); a repo with
1227
+ neither lockfile nor bridge marker reports ``skipped``.
1228
+ """
1229
+ if bridge_present:
1230
+ return {
1231
+ "id": "bridge-drift", "status": "ok",
1232
+ "message": "no project lockfile → distributed-tool drift not "
1233
+ "applicable (global-only consumer)",
1234
+ "remedy": "",
1235
+ }
1236
+ return {
1237
+ "id": "bridge-drift", "status": "skipped",
1238
+ "message": "no project lockfile and no bridge marker → drift check "
1239
+ "not applicable",
1240
+ "remedy": "run `agent-config init` (project install) or "
1241
+ "`agent-config refresh --project` (global-only consumer)",
1242
+ }
1243
+
1244
+
1245
+ def _run_checks_no_manifest(
1246
+ project_root: Path,
1247
+ bridge_present: bool,
1248
+ only: str | None = None,
1249
+ ) -> list[dict[str, Any]]:
1250
+ """Run the registry with no project manifest available.
1251
+
1252
+ Mirrors :func:`_run_checks` and preserves :data:`CHECK_IDS` order.
1253
+ Global checks (:data:`GLOBAL_CHECK_IDS`) run unchanged; manifest-required
1254
+ checks (:data:`MANIFEST_REQUIRED_CHECK_IDS`) report ``skipped``;
1255
+ ``bridge-drift`` gets the scope-aware no-manifest verdict.
1256
+ """
1257
+ runners: dict[str, Any] = {
1258
+ "scope": lambda: _check_scope(project_root),
1259
+ "global-binary": lambda: _check_global_binary(project_root),
1260
+ "manifest-integrity": lambda: _skipped_manifest_check("manifest-integrity"),
1261
+ "lockfile-freshness": lambda: _skipped_manifest_check("lockfile-freshness"),
1262
+ "bridge-drift": lambda: _check_bridge_drift_no_manifest(bridge_present),
1263
+ "mcp-mode": lambda: _check_mcp_mode(project_root),
1264
+ "mcp-beta-readiness": lambda: _check_mcp_beta_readiness(project_root),
1265
+ "offline-readiness": lambda: _check_offline_readiness(),
1266
+ "python-runtime": lambda: _check_python_runtime(),
1267
+ "tier-usage-readiness": lambda: _check_tier_usage_readiness(project_root),
1268
+ "council-cli": lambda: _check_council_cli(project_root),
1269
+ "unsupported-combos": lambda: _skipped_manifest_check("unsupported-combos"),
1270
+ "wizard-state": _check_wizard_state,
1271
+ }
1272
+ out: list[dict[str, Any]] = []
1273
+ for cid in CHECK_IDS:
1274
+ if only is not None and cid != only:
1275
+ continue
1276
+ out.append(runners[cid]())
1277
+ return out
1278
+
1279
+
1280
+ def _run_no_manifest(
1281
+ opts: argparse.Namespace,
1282
+ project_root: Path,
1283
+ origin: str,
1284
+ bridge_present: bool,
1285
+ ) -> int:
1286
+ """Handle the no-project-lockfile path without the old hard bail.
1287
+
1288
+ Exit-code contract (council-defined, 2026-06-02):
1289
+
1290
+ * ``0`` — bare report for a recognised global-only consumer
1291
+ (bridge marker present), or a single global ``--check`` that passed.
1292
+ * ``1`` — a runnable health check requested via ``--check`` failed.
1293
+ * ``2`` — a requested ``--check`` cannot run (manifest-required check
1294
+ with no lockfile, or ``bridge-drift`` with neither lockfile nor
1295
+ bridge marker), or a bare report in an **uninitialised** repo
1296
+ (neither lockfile nor bridge marker) — preserves the spirit of the
1297
+ pre-existing "run init" signal while still printing a real report.
1298
+ """
1299
+ checks = _run_checks_no_manifest(project_root, bridge_present, only=opts.check)
1300
+ fail_check = any(c["status"] == "fail" for c in checks)
1301
+ skipped_requested = opts.check is not None and any(
1302
+ c["id"] == opts.check and c["status"] == "skipped" for c in checks
1303
+ )
1304
+
1305
+ if opts.json:
1306
+ _emit_json(project_root, [], [], [], [], checks=checks, origin=origin)
1307
+ elif opts.check is None:
1308
+ print(f" 📍 project_root: {project_root} (origin: {origin})")
1309
+ if bridge_present:
1310
+ print(" ℹ️ global-only consumer: bridge marker present, no "
1311
+ "project lockfile (expected under ADR-020)")
1312
+ print(" project-manifest checks are skipped — they apply only "
1313
+ "to project-local distributed tools")
1314
+ else:
1315
+ print(" ⚠️ no project lockfile and no bridge marker at "
1316
+ f"{project_root}", file=sys.stderr)
1317
+ print(" run `agent-config init` (project install) or "
1318
+ "`agent-config refresh --project` (global-only consumer)",
1319
+ file=sys.stderr)
1320
+ _emit_checks_text(checks)
1321
+ else:
1322
+ _emit_checks_text(checks)
1323
+
1324
+ if opts.check is not None:
1325
+ if skipped_requested:
1326
+ return 2
1327
+ return 1 if fail_check else 0
1328
+ return 0 if bridge_present else 2
1329
+
1161
1330
 
1162
1331
  def _emit_json(
1163
1332
  project_root: Path,
@@ -1370,17 +1539,12 @@ def main(argv: list[str] | None = None) -> int:
1370
1539
  manifest_pth = installed_tools.manifest_path(project_root)
1371
1540
  manifest = installed_tools.read_manifest(manifest_pth)
1372
1541
  if manifest is None:
1373
- print(
1374
- f"❌ doctor: no project lockfile at {manifest_pth}",
1375
- file=sys.stderr,
1376
- )
1377
- print(
1378
- f" project_root: {project_root} (origin: {origin})",
1379
- file=sys.stderr,
1380
- )
1381
- print(" run `./agent-config init` to create one",
1382
- file=sys.stderr)
1383
- return 2
1542
+ # No project lockfile. Under ADR-020 global-only this is a
1543
+ # legitimate state, not an error — run the lockfile-independent
1544
+ # checks and report consumer state instead of a hard bail. The
1545
+ # per-scope split + exit-code contract live in _run_no_manifest.
1546
+ bridge_present = (project_root / BRIDGE_MARKER_RELATIVE).is_file()
1547
+ return _run_no_manifest(opts, project_root, origin, bridge_present)
1384
1548
 
1385
1549
  records, known = _collect_manifest_entries(project_root, manifest)
1386
1550
  missing, modified, tag_drift = _classify(records)
@@ -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