@event4u/agent-config 2.24.0 → 2.26.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 (161) hide show
  1. package/.agent-src/commands/bug-fix.md +1 -0
  2. package/.agent-src/commands/create-pr/description-only.md +39 -11
  3. package/.agent-src/commands/create-pr.md +59 -5
  4. package/.agent-src/commands/feature/roadmap.md +2 -2
  5. package/.agent-src/commands/fix/seeder.md +3 -2
  6. package/.agent-src/commands/memory/add.md +3 -3
  7. package/.agent-src/commands/module/create.md +1 -0
  8. package/.agent-src/commands/module/explore.md +10 -6
  9. package/.agent-src/commands/onboard.md +9 -1
  10. package/.agent-src/commands/optimize/augmentignore.md +52 -20
  11. package/.agent-src/commands/optimize/rtk.md +56 -30
  12. package/.agent-src/commands/package-test.md +86 -10
  13. package/.agent-src/commands/quality-fix.md +49 -27
  14. package/.agent-src/commands/update-form-request-messages.md +2 -1
  15. package/.agent-src/commands/video/from-script.md +5 -5
  16. package/.agent-src/commands/video/storyboard.md +1 -1
  17. package/.agent-src/contexts/augment-infrastructure.md +4 -7
  18. package/.agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -1
  19. package/.agent-src/contexts/contracts/research-schema.md +1 -1
  20. package/.agent-src/contexts/execution/interrupt-examples.md +34 -0
  21. package/.agent-src/contexts/execution/roadmap-process-loop.md +69 -14
  22. package/.agent-src/contexts/skills-and-commands.md +2 -2
  23. package/.agent-src/personas/README.md +3 -2
  24. package/.agent-src/personas/ai-video-technical-director.md +2 -2
  25. package/.agent-src/personas/hollywood-director.md +3 -3
  26. package/.agent-src/profiles/content_creator.yml +5 -0
  27. package/.agent-src/rules/architecture.md +24 -10
  28. package/.agent-src/rules/artifact-drafting-protocol.md +6 -0
  29. package/.agent-src/rules/augment-edit-discipline.md +28 -0
  30. package/.agent-src/rules/augment-source-of-truth.md +2 -2
  31. package/.agent-src/rules/autonomous-execution.md +31 -0
  32. package/.agent-src/rules/context-hygiene.md +1 -1
  33. package/.agent-src/rules/domain-adoption-policy.md +4 -5
  34. package/.agent-src/rules/domain-safety-disclaimer.md +114 -0
  35. package/.agent-src/rules/domain-safety-pii.md +142 -0
  36. package/.agent-src/rules/domain-safety-retention.md +86 -0
  37. package/.agent-src/rules/downstream-changes.md +4 -4
  38. package/.agent-src/rules/framework-neutrality-in-generic-skills.md +130 -0
  39. package/.agent-src/rules/git-history-discipline.md +99 -0
  40. package/.agent-src/rules/media-governance-routing.md +82 -0
  41. package/.agent-src/rules/minimal-safe-diff.md +6 -0
  42. package/.agent-src/rules/no-roadmap-references.md +4 -2
  43. package/.agent-src/rules/persona-governance.md +90 -0
  44. package/.agent-src/rules/provider-lifecycle-discipline.md +75 -0
  45. package/.agent-src/rules/roadmap-ci-steps-policy.md +145 -0
  46. package/.agent-src/rules/roadmap-progress-sync.md +11 -5
  47. package/.agent-src/rules/user-interrupt-priority.md +46 -0
  48. package/.agent-src/rules/verify-before-complete.md +11 -2
  49. package/.agent-src/skills/adversarial-review/SKILL.md +1 -1
  50. package/.agent-src/skills/ai-council/SKILL.md +1 -0
  51. package/.agent-src/skills/api-endpoint/SKILL.md +58 -154
  52. package/.agent-src/skills/api-testing/SKILL.md +11 -0
  53. package/.agent-src/skills/character-consistency/SKILL.md +12 -1
  54. package/.agent-src/skills/code-refactoring/SKILL.md +36 -30
  55. package/.agent-src/skills/code-review/SKILL.md +41 -36
  56. package/.agent-src/skills/context-authoring/SKILL.md +1 -1
  57. package/.agent-src/skills/dashboard-design/SKILL.md +1 -2
  58. package/.agent-src/skills/database/SKILL.md +8 -3
  59. package/.agent-src/skills/dependency-upgrade/SKILL.md +65 -19
  60. package/.agent-src/skills/developer-like-execution/SKILL.md +25 -14
  61. package/.agent-src/skills/eloquent/SKILL.md +1 -1
  62. package/.agent-src/skills/feature-planning/SKILL.md +1 -1
  63. package/.agent-src/skills/file-editor/SKILL.md +45 -19
  64. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  65. package/.agent-src/skills/git-workflow/SKILL.md +135 -2
  66. package/.agent-src/skills/laravel-api-endpoint/SKILL.md +187 -0
  67. package/.agent-src/skills/{dto-creator → laravel-dto}/SKILL.md +5 -4
  68. package/.agent-src/skills/{migration-creator → laravel-migration}/SKILL.md +11 -10
  69. package/.agent-src/skills/laravel-reverb/SKILL.md +3 -3
  70. package/.agent-src/skills/{websocket → laravel-websocket}/SKILL.md +4 -3
  71. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
  72. package/.agent-src/skills/merge-conflicts/SKILL.md +49 -17
  73. package/.agent-src/skills/migration-architect/SKILL.md +6 -6
  74. package/.agent-src/skills/module-management/SKILL.md +1 -0
  75. package/.agent-src/skills/motion-choreographer/SKILL.md +12 -0
  76. package/.agent-src/skills/multi-tenancy/SKILL.md +15 -8
  77. package/.agent-src/skills/pest-testing/SKILL.md +18 -0
  78. package/.agent-src/skills/php-debugging/SKILL.md +28 -0
  79. package/.agent-src/skills/php-service/SKILL.md +3 -3
  80. package/.agent-src/skills/pixar-storyteller/SKILL.md +19 -6
  81. package/.agent-src/skills/playwright-testing/SKILL.md +16 -1
  82. package/.agent-src/skills/project-analyzer/SKILL.md +68 -42
  83. package/.agent-src/skills/readme-writing-package/SKILL.md +94 -23
  84. package/.agent-src/skills/roadmap-management/SKILL.md +1 -1
  85. package/.agent-src/skills/roadmap-writing/SKILL.md +10 -0
  86. package/.agent-src/skills/rtk-output-filtering/SKILL.md +23 -8
  87. package/.agent-src/skills/rule-refactor/SKILL.md +145 -0
  88. package/.agent-src/skills/rule-writing/SKILL.md +34 -8
  89. package/.agent-src/skills/scene-expander/SKILL.md +22 -7
  90. package/.agent-src/skills/security/SKILL.md +38 -29
  91. package/.agent-src/skills/skill-reviewer/SKILL.md +1 -1
  92. package/.agent-src/skills/test-driven-development/SKILL.md +4 -4
  93. package/.agent-src/skills/test-performance/SKILL.md +6 -5
  94. package/.agent-src/skills/verify-completion-evidence/SKILL.md +24 -27
  95. package/.agent-src/skills/video-director/SKILL.md +13 -0
  96. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/.agent-src/templates/copilot-instructions.md +2 -2
  98. package/.agent-src/templates/roadmaps.md +16 -0
  99. package/.agent-src/templates/rule.md +2 -2
  100. package/.claude-plugin/marketplace.json +6 -4
  101. package/AGENTS.md +1 -1
  102. package/CHANGELOG.md +80 -133
  103. package/README.md +6 -4
  104. package/config/agent-settings.template.yml +26 -0
  105. package/docs/architecture.md +2 -2
  106. package/docs/archive/CHANGELOG-pre-2.25.0.md +191 -0
  107. package/docs/catalog.md +20 -12
  108. package/docs/contracts/file-ownership-matrix.json +588 -90
  109. package/docs/contracts/kernel-membership.md +17 -0
  110. package/docs/contracts/provider-lifecycle.md +122 -0
  111. package/docs/contracts/smoke-contracts.md +8 -8
  112. package/docs/decisions/ADR-011-domain-pack-readiness.md +213 -0
  113. package/docs/decisions/INDEX.md +1 -0
  114. package/docs/getting-started-by-role.md +10 -0
  115. package/docs/getting-started.md +1 -1
  116. package/docs/guidelines/php/api-design.md +1 -1
  117. package/docs/guidelines/php/controllers.md +1 -1
  118. package/docs/guidelines/php/resources.md +1 -1
  119. package/docs/guidelines/php/validations.md +1 -1
  120. package/docs/personas.md +73 -26
  121. package/docs/profiles.md +9 -4
  122. package/package.json +1 -1
  123. package/scripts/_tmp_scan_framework_leakage.py +119 -0
  124. package/scripts/ai-video/adapters/gemini-veo.sh +5 -0
  125. package/scripts/ai-video/adapters/higgsfield.sh +6 -0
  126. package/scripts/ai-video/adapters/kling.sh +5 -0
  127. package/scripts/ai-video/adapters/openai-images.sh +5 -0
  128. package/scripts/ai-video/adapters/sora.sh +6 -0
  129. package/scripts/build_linear_digest.py +0 -1
  130. package/scripts/check_portability.py +6 -0
  131. package/scripts/lint_framework_leakage.py +348 -0
  132. package/scripts/lint_framework_leakage_allowlist.json +476 -0
  133. package/scripts/lint_media_policy_linkage.py +140 -0
  134. package/scripts/lint_persona_governance.py +164 -0
  135. package/scripts/lint_roadmap_ci_steps.py +182 -0
  136. package/scripts/measure_augment_budget.py +6 -0
  137. package/scripts/schemas/command.schema.json +5 -0
  138. package/scripts/schemas/skill.schema.json +5 -0
  139. package/scripts/skill_linter.py +60 -7
  140. package/scripts/smoke/kernel.sh +4 -4
  141. package/scripts/smoke/router.sh +2 -2
  142. package/scripts/smoke/schema.sh +1 -1
  143. package/.agent-src/personas/pixar-storyboard-artist.md +0 -98
  144. package/.agent-src/rules/agent-docs.md +0 -20
  145. package/.agent-src/rules/augment-portability.md +0 -23
  146. package/.agent-src/rules/capture-learnings.md +0 -19
  147. package/.agent-src/rules/docs-sync.md +0 -20
  148. package/.agent-src/rules/domain-safety-disclaimer-consulting.md +0 -52
  149. package/.agent-src/rules/domain-safety-disclaimer-financial.md +0 -54
  150. package/.agent-src/rules/domain-safety-disclaimer-legal.md +0 -49
  151. package/.agent-src/rules/domain-safety-disclaimer-medical.md +0 -56
  152. package/.agent-src/rules/domain-safety-export-redact.md +0 -65
  153. package/.agent-src/rules/domain-safety-logging-pii-floor.md +0 -55
  154. package/.agent-src/rules/domain-safety-pii-finance.md +0 -57
  155. package/.agent-src/rules/domain-safety-pii-marketing.md +0 -60
  156. package/.agent-src/rules/domain-safety-pii-recruiting.md +0 -56
  157. package/.agent-src/rules/domain-safety-pii-support.md +0 -57
  158. package/.agent-src/rules/domain-safety-retention-finance.md +0 -48
  159. package/.agent-src/rules/domain-safety-retention-support.md +0 -55
  160. package/.agent-src/rules/e2e-testing.md +0 -19
  161. package/.agent-src/rules/no-unsolicited-rebase.md +0 -107
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env python3
2
+ """Lint persona governance — per-domain cap (hard) + citation floor (warn).
3
+
4
+ Enforces the mechanical checks in
5
+ `.agent-src.uncompressed/rules/persona-governance.md`:
6
+
7
+ 1. **Per-domain cap (HARD)** — ≤ 2 active specialist personas per
8
+ content domain. Core-tier personas are exempt. `status:
9
+ deprecated` rows (if any survive a transition window) are
10
+ excluded from the count; the canonical path is in-commit
11
+ deletion, no soak window.
12
+ 2. **Skill citation floor (WARN)** — every active specialist
13
+ persona SHOULD be cited by `personas: [<id>]` in at least one
14
+ skill SKILL.md under `.agent-src.uncompressed/skills/` or
15
+ `.claude/skills/`. Surfaced as a warning, never blocks CI:
16
+ the citation floor is enforced at PR time per the rule (a new
17
+ specialist MUST land with a cite); pre-existing wiring debt is
18
+ tracked as `--citation-debt` for the maintainer dashboard.
19
+
20
+ Schema conformance (check 4) is delegated to `lint-skills`.
21
+ Deprecation path (check 3) is reviewed at PR time via the table in
22
+ `docs/personas.md`.
23
+
24
+ Domain inference: persona ids → content domain via `DOMAIN_MAP`,
25
+ mirroring `persona-governance.md § Per-domain cap`. Personas absent
26
+ from the map are cross-cutting (uncapped).
27
+
28
+ Exit codes:
29
+ 0 per-domain cap clean (citation warnings non-blocking)
30
+ 1 per-domain cap violated
31
+ """
32
+ from __future__ import annotations
33
+
34
+ import re
35
+ import sys
36
+ from collections import defaultdict
37
+ from pathlib import Path
38
+
39
+ QUIET = "--quiet" in sys.argv
40
+
41
+ REPO = Path(__file__).resolve().parents[1]
42
+ PERSONA_DIR = REPO / ".agent-src.uncompressed" / "personas"
43
+ SKILL_ROOTS: tuple[Path, ...] = (
44
+ REPO / ".agent-src.uncompressed" / "skills",
45
+ REPO / ".claude" / "skills",
46
+ )
47
+
48
+ # Per-domain cap — mirrors persona-governance.md § Per-domain cap.
49
+ # Maps persona id → content-domain bucket. Personas absent from this
50
+ # map are cross-cutting (uncapped) — typically singleton specialists
51
+ # without a domain peer (e.g. `qa`, `tech-writer`).
52
+ DOMAIN_MAP: dict[str, str] = {
53
+ "hollywood-director": "ai-video",
54
+ "ai-video-technical-director": "ai-video",
55
+ "backend-architect": "backend",
56
+ "eloquent-tamer": "backend",
57
+ "cmo": "gtm",
58
+ "revops": "gtm",
59
+ "growth-pm": "growth",
60
+ "customer-success-lead": "customer",
61
+ "discovery-lead": "customer",
62
+ "engineering-manager": "people",
63
+ "people-strategist": "people",
64
+ "finance-partner": "money",
65
+ "strategist": "money",
66
+ }
67
+ PER_DOMAIN_CAP = 2
68
+
69
+
70
+ def emit(msg: str) -> None:
71
+ if not QUIET:
72
+ print(msg)
73
+
74
+
75
+ def parse_frontmatter(path: Path) -> dict[str, str]:
76
+ text = path.read_text(encoding="utf-8", errors="replace")
77
+ if not text.startswith("---"):
78
+ return {}
79
+ end = text.find("\n---", 3)
80
+ if end == -1:
81
+ return {}
82
+ out: dict[str, str] = {}
83
+ for line in text[3:end].splitlines():
84
+ m = re.match(r"^([a-zA-Z_][\w-]*):\s*(.*)$", line)
85
+ if m:
86
+ out[m.group(1)] = m.group(2).strip().strip('"').strip("'")
87
+ return out
88
+
89
+
90
+ def collect_personas() -> list[tuple[str, str, str, Path]]:
91
+ """Return (id, tier, status, path) for every persona file."""
92
+ out: list[tuple[str, str, str, Path]] = []
93
+ if not PERSONA_DIR.exists():
94
+ return out
95
+ for path in sorted(PERSONA_DIR.glob("*.md")):
96
+ if path.stem == "README":
97
+ continue
98
+ fm = parse_frontmatter(path)
99
+ pid = fm.get("id") or path.stem
100
+ tier = fm.get("tier", "")
101
+ status = fm.get("status", "active") or "active"
102
+ out.append((pid, tier, status, path))
103
+ return out
104
+
105
+
106
+ def citations_for(persona_id: str) -> list[Path]:
107
+ pattern = re.compile(rf"(^|[\s,\[]){re.escape(persona_id)}([\s,\]]|$)")
108
+ hits: list[Path] = []
109
+ for root in SKILL_ROOTS:
110
+ if not root.exists():
111
+ continue
112
+ for skill in root.rglob("SKILL.md"):
113
+ text = skill.read_text(encoding="utf-8", errors="replace")
114
+ if text.startswith("---"):
115
+ end = text.find("\n---", 3)
116
+ fm_block = text[3:end] if end != -1 else ""
117
+ else:
118
+ fm_block = ""
119
+ if "personas:" not in fm_block:
120
+ continue
121
+ if pattern.search(fm_block):
122
+ hits.append(skill)
123
+ return hits
124
+
125
+
126
+ def main() -> int:
127
+ personas = collect_personas()
128
+ if not personas:
129
+ emit("persona-governance: no persona files found — nothing to lint.")
130
+ return 0
131
+
132
+ by_domain: dict[str, list[str]] = defaultdict(list)
133
+ missing_citations: list[str] = []
134
+
135
+ for pid, tier, status, _ in personas:
136
+ if status == "deprecated" or tier != "specialist":
137
+ continue
138
+ domain = DOMAIN_MAP.get(pid)
139
+ if domain:
140
+ by_domain[domain].append(pid)
141
+ if not citations_for(pid):
142
+ missing_citations.append(pid)
143
+
144
+ overflows = {d: ids for d, ids in by_domain.items() if len(ids) > PER_DOMAIN_CAP}
145
+ for d, ids in sorted(by_domain.items()):
146
+ marker = "❌" if d in overflows else "✅"
147
+ emit(f"{marker} domain={d} {len(ids)}/{PER_DOMAIN_CAP} {', '.join(sorted(ids))}")
148
+ for pid in sorted(missing_citations):
149
+ emit(f"⚠️ no-skill-citation {pid} (warn — see PR-time gate)")
150
+
151
+ if overflows:
152
+ print("\npersona-governance: per-domain cap violated.", file=sys.stderr)
153
+ for d, ids in sorted(overflows.items()):
154
+ print(f" - domain '{d}' has {len(ids)} specialists (cap {PER_DOMAIN_CAP}): {', '.join(sorted(ids))}", file=sys.stderr)
155
+ return 1
156
+
157
+ active = sum(1 for _, t, s, _ in personas if s != "deprecated" and t == "specialist")
158
+ cited = active - len(missing_citations)
159
+ emit(f"persona-governance: {active} active specialist persona(s) — all domains within cap; {cited}/{active} cited by ≥ 1 skill.")
160
+ return 0
161
+
162
+
163
+ if __name__ == "__main__":
164
+ sys.exit(main())
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env python3
2
+ """Hard-Gate linter for the ``roadmap-ci-steps-policy`` rule.
3
+
4
+ Forbids full-pipeline CI literals (``task ci``, ``make test``,
5
+ ``npm run check`` etc.) inside ``agents/roadmaps/*.md`` checkbox steps
6
+ or fenced bash blocks **when** ``quality.local_auto_run`` in
7
+ ``.agent-settings.yml`` is ``false``.
8
+
9
+ Carve-outs:
10
+ * Setting is ``true`` → linter no-ops (exit 0).
11
+ * Step line carries ``<!-- carve-out: new-gate-verification -->`` →
12
+ allowed (new gate added by the same roadmap).
13
+ * ``## Acceptance criteria`` section → documentation, not steps.
14
+ * ``agents/roadmaps/archive/`` and ``agents/roadmaps/skipped/`` → out
15
+ of scope; they record history.
16
+
17
+ Cap: ≤ 150 LOC, stdlib only. Hooked into ``task ci-fast`` via
18
+ ``task lint-roadmap-ci-steps``.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import re
23
+ import sys
24
+ from pathlib import Path
25
+
26
+ QUIET = "--quiet" in sys.argv
27
+
28
+ REPO_ROOT = Path(__file__).resolve().parent.parent
29
+ ROADMAP_GLOB = "agents/roadmaps/*.md"
30
+ SETTINGS_FILE = REPO_ROOT / ".agent-settings.yml"
31
+ LOCAL_AUTO_RUN_PAT = re.compile(
32
+ r"^\s*local_auto_run:\s*(true|false)\s*(?:#.*)?$", re.MULTILINE
33
+ )
34
+ CARVE_OUT_MARKER = "carve-out: new-gate-verification"
35
+
36
+ # CI-shaped literals — case-insensitive whole-word(-ish) matches.
37
+ CI_PATTERNS: tuple[tuple[re.Pattern[str], str], ...] = (
38
+ (re.compile(r"\btask\s+ci-strict\b", re.IGNORECASE), "task ci-strict"),
39
+ (re.compile(r"\btask\s+ci-fast\b", re.IGNORECASE), "task ci-fast"),
40
+ (re.compile(r"\btask\s+ci\b(?!-)", re.IGNORECASE), "task ci"),
41
+ (re.compile(r"\bmake\s+ci\b", re.IGNORECASE), "make ci"),
42
+ (re.compile(r"\bmake\s+test\b", re.IGNORECASE), "make test"),
43
+ (re.compile(r"\bnpm\s+run\s+check\b", re.IGNORECASE), "npm run check"),
44
+ (re.compile(r"\bpnpm\s+run\s+check\b", re.IGNORECASE), "pnpm run check"),
45
+ (re.compile(r"\byarn\s+check\b", re.IGNORECASE), "yarn check"),
46
+ (re.compile(r"\bcomposer\s+test\b", re.IGNORECASE), "composer test"),
47
+ # Whole-suite = bare command, or command followed only by prose
48
+ # ("before the boundary"). A real shell argument starts with ``-``
49
+ # (flag) or contains ``/`` or ``.`` (path / .php file) — that
50
+ # signals a targeted run and is allowed.
51
+ (re.compile(r"\bvendor/bin/phpunit\b(?!\s+(?:-|\S*[/.]))", re.IGNORECASE),
52
+ "vendor/bin/phpunit (whole suite)"),
53
+ (re.compile(r"\bphp\s+artisan\s+test\b(?!\s+(?:-|\S*[/.]))", re.IGNORECASE),
54
+ "php artisan test (whole suite)"),
55
+ )
56
+
57
+ CHECKBOX_PAT = re.compile(r"^\s*-\s*\[[ x~/-]\]\s")
58
+ FENCE_PAT = re.compile(r"^\s*```")
59
+ HEADING_PAT = re.compile(r"^(#{1,6})\s+(.*?)\s*$")
60
+ ACCEPTANCE_HEADING_PAT = re.compile(
61
+ r"^acceptance criteria\b", re.IGNORECASE
62
+ )
63
+
64
+
65
+ def _read_local_auto_run() -> bool:
66
+ """Return ``quality.local_auto_run`` from ``.agent-settings.yml``.
67
+
68
+ Default ``True`` (= no-op) when file or key is missing. The Hard
69
+ Gate only fires when the setting is explicitly ``false``.
70
+ """
71
+ if not SETTINGS_FILE.is_file():
72
+ return True
73
+ try:
74
+ text = SETTINGS_FILE.read_text(encoding="utf-8")
75
+ except OSError:
76
+ return True
77
+ in_quality = False
78
+ for raw in text.splitlines():
79
+ if not raw.strip() or raw.lstrip().startswith("#"):
80
+ continue
81
+ if raw.startswith("quality:"):
82
+ in_quality = True
83
+ continue
84
+ if in_quality and raw and not raw.startswith((" ", "\t")):
85
+ in_quality = False
86
+ continue
87
+ if in_quality:
88
+ m = LOCAL_AUTO_RUN_PAT.match(raw)
89
+ if m:
90
+ return m.group(1).lower() == "true"
91
+ return True
92
+
93
+
94
+ def _scan(text: str) -> list[tuple[int, str, str]]:
95
+ """Return ``(line_no, matched_literal, line_text)`` for every hit.
96
+
97
+ Only scans:
98
+ * checkbox-step lines (``- [ ] …``)
99
+ * lines inside fenced code blocks (```` ``` ````)
100
+ Skips lines under an ``## Acceptance criteria`` heading.
101
+ Skips lines carrying the carve-out marker.
102
+ """
103
+ hits: list[tuple[int, str, str]] = []
104
+ in_fence = False
105
+ in_acceptance = False
106
+ for idx, line in enumerate(text.splitlines(), start=1):
107
+ if FENCE_PAT.match(line):
108
+ in_fence = not in_fence
109
+ continue
110
+ if not in_fence:
111
+ heading = HEADING_PAT.match(line)
112
+ if heading:
113
+ in_acceptance = bool(
114
+ ACCEPTANCE_HEADING_PAT.match(heading.group(2))
115
+ )
116
+ continue
117
+ if in_acceptance:
118
+ continue
119
+ is_checkbox = CHECKBOX_PAT.match(line) is not None
120
+ if not (is_checkbox or in_fence):
121
+ continue
122
+ if CARVE_OUT_MARKER in line:
123
+ continue
124
+ for pat, label in CI_PATTERNS:
125
+ if pat.search(line):
126
+ hits.append((idx, label, line.strip()))
127
+ break
128
+ return hits
129
+
130
+
131
+ def main() -> int:
132
+ if _read_local_auto_run():
133
+ if not QUIET:
134
+ print(
135
+ "✅ quality.local_auto_run=true (or unset) — "
136
+ "CI-step gate disabled"
137
+ )
138
+ return 0
139
+ roadmaps = sorted(REPO_ROOT.glob(ROADMAP_GLOB))
140
+ if not roadmaps:
141
+ if not QUIET:
142
+ print(f"✅ no active roadmaps under {ROADMAP_GLOB}")
143
+ return 0
144
+ failed = 0
145
+ for roadmap in roadmaps:
146
+ rel = roadmap.relative_to(REPO_ROOT)
147
+ text = roadmap.read_text(encoding="utf-8")
148
+ hits = _scan(text)
149
+ if hits:
150
+ failed += 1
151
+ print(f"❌ {rel}", file=sys.stderr)
152
+ for line_no, label, line_text in hits:
153
+ print(
154
+ f" line {line_no}: '{label}' in: {line_text}",
155
+ file=sys.stderr,
156
+ )
157
+ print(
158
+ " → reword as a narrow command "
159
+ "(e.g. 'vendor/bin/phpstan analyse app/Modules/X'), or "
160
+ "mark with '<!-- carve-out: new-gate-verification -->' "
161
+ "when the step verifies a NEW gate introduced by this "
162
+ "roadmap.",
163
+ file=sys.stderr,
164
+ )
165
+ else:
166
+ if not QUIET:
167
+ print(f"✅ {rel}")
168
+ if failed:
169
+ print(
170
+ f"\n❌ {failed} roadmap(s) schedule full-pipeline CI steps "
171
+ f"while quality.local_auto_run=false — "
172
+ f"see .augment/rules/roadmap-ci-steps-policy.md",
173
+ file=sys.stderr,
174
+ )
175
+ return 1
176
+ if not QUIET:
177
+ print(f"\n✅ {len(roadmaps)} roadmap(s) CI-step-clean")
178
+ return 0
179
+
180
+
181
+ if __name__ == "__main__":
182
+ sys.exit(main())
@@ -42,6 +42,12 @@ RULES_DIR = REPO_ROOT / ".augment" / "rules"
42
42
  TREND_FILE = REPO_ROOT / "agents" / ".augment-budget-history.jsonl"
43
43
 
44
44
  # Augment workspace-guidelines ceiling — empirical 2026-05-08.
45
+ # TOTAL_CAP is the hard ceiling Augment itself enforces. FAIL_THRESHOLD is the
46
+ # soft safety-margin gate (0.95). When a branch breaches it, the discipline
47
+ # is: DO NOT loosen the threshold — invoke the `rule-refactor` skill, which
48
+ # audits all rules for merge / delete / move-to-context / promote-to-skill
49
+ # candidates. Threshold-lift is explicitly rejected as a tool-shape anti-
50
+ # pattern (see the validation-budget rule). Only an ADR may grow the cap.
45
51
  TOTAL_CAP = 49_512
46
52
  WARN_THRESHOLD = 0.85
47
53
  FAIL_THRESHOLD = 0.95
@@ -67,6 +67,11 @@
67
67
  "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
68
68
  "description": "Semver release in which this command became a shim (e.g. '1.15.0')."
69
69
  },
70
+ "framework": {
71
+ "type": "string",
72
+ "pattern": "^[a-z][a-z0-9-]*$",
73
+ "description": "Framework carve-out marker. Set on commands that are 100% coupled to one stack (e.g. `framework: laravel` on update-form-request-messages). Generic, multi-stack commands MUST omit this key. Routed by .agent-src.uncompressed/rules/framework-neutrality-in-generic-skills.md (Tier 2)."
74
+ },
70
75
  "council_depth": {
71
76
  "type": "string",
72
77
  "enum": ["deep"],
@@ -35,6 +35,11 @@
35
35
  "type": "string",
36
36
  "pattern": "^[a-z][a-z0-9-]*$"
37
37
  },
38
+ "framework": {
39
+ "type": "string",
40
+ "pattern": "^[a-z][a-z0-9-]*$",
41
+ "description": "Framework carve-out marker. Set on skills that are 100% coupled to one stack (e.g. `framework: laravel` on laravel-* skills). Generic, multi-stack skills MUST omit this key. Routed by .agent-src.uncompressed/rules/framework-neutrality-in-generic-skills.md (Tier 2)."
42
+ },
38
43
  "personas": {
39
44
  "type": "array",
40
45
  "items": {
@@ -472,6 +472,21 @@ def _command_delegation_signal(text: str, frontmatter: Optional[str]) -> bool:
472
472
  return False
473
473
 
474
474
 
475
+ def _strip_markdown_for_check(text: str) -> str:
476
+ """Strip fenced code, inline code spans, and markdown links so heuristic
477
+ regex matches operate on prose only.
478
+
479
+ Used by rule-body heuristics whose targets (e.g. ``procedural_rule``)
480
+ must not flip on legitimate skill pointers like ``[git-workflow](…)``
481
+ or ``` `skill:symfony-workflow` ```. Frontmatter is handled by the
482
+ caller via ``text.split("---", 2)[-1]``.
483
+ """
484
+ text = re.sub(r"```[^\n]*\n.*?```", "", text, flags=re.DOTALL)
485
+ text = re.sub(r"`[^`\n]+`", "", text)
486
+ text = re.sub(r"\[[^\]]*\]\([^)]*\)", "", text)
487
+ return text
488
+
489
+
475
490
  def _iron_law_blocks(text: str) -> int:
476
491
  """Count fenced blocks that look like verbatim Iron-Law imperatives.
477
492
 
@@ -575,10 +590,36 @@ def has_validation_step(procedure_block: str) -> bool:
575
590
  return any(signal in lowered for signal in good_signals)
576
591
 
577
592
 
593
+ _INSPECT_VERB_PATTERN = re.compile(
594
+ r"\b(?:"
595
+ # Direct inspection
596
+ r"inspect|examine|audit|survey"
597
+ # Read / look
598
+ r"|read|look\s+at"
599
+ # Check (word-boundary — matches "check that", "check current", "check what")
600
+ r"|check"
601
+ # Review (broad — matches "review existing", "review the failures")
602
+ r"|review"
603
+ # Comprehension / orientation
604
+ r"|understand|identify|analyze|analyse"
605
+ # Discovery
606
+ r"|detect|gather|discover"
607
+ r")\b",
608
+ re.IGNORECASE,
609
+ )
610
+
611
+
578
612
  def has_inspect_step(procedure_block: str) -> bool:
579
- lowered = procedure_block.lower()
580
- inspect_signals = ["inspect", "check current", "review existing", "identify", "analyze"]
581
- return any(signal in lowered for signal in inspect_signals)
613
+ """Return True if the procedure block opens with an inspect / read step.
614
+
615
+ Corpus-driven verb list (see docs/contracts/linter-structural-model.md):
616
+ the first ordered step in a skill procedure should orient the agent in
617
+ the live system — read existing code, examine current state, detect
618
+ stack — before mutating anything. Regex uses word boundaries to avoid
619
+ substring matches inside unrelated words (e.g. ``read`` inside
620
+ ``already``).
621
+ """
622
+ return bool(_INSPECT_VERB_PATTERN.search(procedure_block))
582
623
 
583
624
 
584
625
  def find_vague_validation(text: str) -> list[str]:
@@ -678,8 +719,9 @@ def lint_skill(path: Path, text: str) -> LintResult:
678
719
  if skill_name and "-" not in skill_name and len(skill_name) >= 3:
679
720
  # Single word without qualifier — likely too generic
680
721
  ALLOWED_BARE_NOUNS = {"database", "devcontainer", "docker", "eloquent", "flux", "forecasting",
681
- "grafana", "laravel", "livewire", "mcp", "openapi", "performance",
682
- "security", "terraform", "terragrunt", "traefik", "websocket"}
722
+ "grafana", "laravel", "livewire", "markitdown", "mcp", "openapi",
723
+ "performance", "security", "terraform", "terragrunt", "traefik",
724
+ "websocket"}
683
725
  if skill_name.lower() not in ALLOWED_BARE_NOUNS:
684
726
  issues.append(Issue("warning", "bare_noun_name",
685
727
  f"Bare-noun skill name `{skill_name}` — consider adding a qualifier (e.g., `{skill_name}-management`)"))
@@ -1504,9 +1546,20 @@ def lint_rule(path: Path, text: str) -> LintResult:
1504
1546
  if bad_sign in text:
1505
1547
  issues.append(Issue("error", "rule_looks_like_skill", f"Rule contains skill-like section: {bad_sign}"))
1506
1548
 
1507
- # Exclude frontmatter from procedural check (frontmatter may contain "type")
1549
+ # Procedural-rule heuristic: a rule "looks procedural" only when its own
1550
+ # prose AND its own structure both signal a procedure. We:
1551
+ # 1. Exclude frontmatter (may contain "type", path strings, etc.).
1552
+ # 2. Strip code spans, fenced blocks, and markdown links — so legitimate
1553
+ # pointers to procedural skills (e.g. `skill:git-workflow`,
1554
+ # [symfony-workflow](…)) do not flip the keyword count.
1555
+ # 3. Require ≥ 2 keyword occurrences in stripped prose AND ≥ 3 ordered
1556
+ # steps AND no Iron-Law block — that combination distinguishes a
1557
+ # mis-classified procedure from a rule that merely references one.
1508
1558
  body = text.split("---", 2)[-1] if frontmatter else text
1509
- if re.search(r"\b(procedure|workflow)\b", body, re.IGNORECASE):
1559
+ stripped_body = _strip_markdown_for_check(body)
1560
+ kw_count = len(re.findall(r"\b(procedure|workflow)\b", stripped_body, re.IGNORECASE))
1561
+ ordered_steps = len(re.findall(r"^\s*\d+\.\s+", body, re.MULTILINE))
1562
+ if kw_count >= 2 and ordered_steps >= 3 and _iron_law_blocks(text) == 0:
1510
1563
  issues.append(Issue("warning", "procedural_rule", "Rule looks procedural; consider a skill instead"))
1511
1564
 
1512
1565
  return LintResult(
@@ -2,9 +2,9 @@
2
2
  # scripts/smoke/kernel.sh — kernel-tier smoke (step-11 Phase 3 Step 2).
3
3
  #
4
4
  # Asserts:
5
- # 1. router.json lists exactly 9 kernel rules.
5
+ # 1. router.json lists exactly 10 kernel rules.
6
6
  # 2. Every kernel rule file exists at .agent-src/rules/<id>.md.
7
- # 3. 8 of 9 carry at least one Iron-Law fenced block.
7
+ # 3. 9 of 10 carry at least one Iron-Law fenced block.
8
8
  # agent-authority is the dispatch index, exempt from the fence
9
9
  # requirement (docs/contracts/smoke-contracts.md § 3.1).
10
10
  # 4. Kernel-bucket char budget breaches ≤ EXPECTED_BREACHES.
@@ -16,8 +16,8 @@
16
16
 
17
17
  set -euo pipefail
18
18
 
19
- EXPECTED_KERNEL_COUNT=9
20
- EXPECTED_FENCE_CARRIERS=8
19
+ EXPECTED_KERNEL_COUNT=10
20
+ EXPECTED_FENCE_CARRIERS=9
21
21
  EXPECTED_BREACHES=2
22
22
  EXEMPT_FROM_FENCE="agent-authority"
23
23
 
@@ -2,7 +2,7 @@
2
2
  # scripts/smoke/router.sh — router-tier smoke (step-11 Phase 3 Step 3).
3
3
  #
4
4
  # Asserts router.json structural integrity:
5
- # 1. 75 ids = 9 kernel + 24 tier_1 + 42 tier_2 (locked count).
5
+ # 1. 68 ids = 10 kernel + 23 tier_1 + 35 tier_2 (locked count).
6
6
  # 2. Every id resolves to .agent-src/rules/<id>.md (0 broken).
7
7
  # 3. Every routes_to ref resolves through its prefix
8
8
  # (skill:, command:, guideline:, contract:); missing-contract
@@ -15,7 +15,7 @@
15
15
 
16
16
  set -euo pipefail
17
17
 
18
- EXPECTED_TOTAL_IDS=75
18
+ EXPECTED_TOTAL_IDS=68
19
19
  EXPECTED_MISSING_CONTRACTS=2
20
20
 
21
21
  quiet="${SMOKE_QUIET:-0}"
@@ -18,7 +18,7 @@
18
18
 
19
19
  set -euo pipefail
20
20
 
21
- EXPECTED_WARNS=92
21
+ EXPECTED_WARNS=93
22
22
  EXPECTED_MIN_TOTAL=438
23
23
 
24
24
  quiet="${SMOKE_QUIET:-0}"
@@ -1,98 +0,0 @@
1
- ---
2
- id: pixar-storyboard-artist
3
- role: Pixar Storyboard Artist
4
- description: "Senior animation storyboard artist — names the emotional beat, the acting choice, the environment that reacts, and refuses flat reads."
5
- tier: specialist
6
- mode: developer
7
- version: "1.0"
8
- source: package
9
- ---
10
-
11
- # Pixar Storyboard Artist
12
-
13
- ## Focus
14
-
15
- The acting read of a scene. A prompt is done when the character
16
- *wants* something, the environment *responds* to them, and one
17
- emotional beat is unambiguous in the frame. Refuses flat reads —
18
- eyes-open, mouth-shut, hands-at-sides — and demands acting choices
19
- the camera can pick up. Not responsible for live-action lensing
20
- (`hollywood-director`) or provider grammar (`ai-video-technical-director`).
21
-
22
- ## Mindset
23
-
24
- - A scene without a want is a still life. The character is reaching
25
- for something — name it.
26
- - Eyes carry the read. Eye line, blink rhythm, micro-glance — these
27
- are the acting, not the body pose.
28
- - The environment is a co-star. Leaves move because the wind moves;
29
- the wind moves because the moment shifts.
30
- - Anticipation → action → reaction is a unit. Skip anticipation and
31
- the action looks teleported.
32
- - Stylization is a choice, not a default. "Pixar-style" without a
33
- specific film reference is a wishlist, not a brief.
34
-
35
- ## Unique Questions
36
-
37
- - What does the character want in this beat, and what is in their way?
38
- - Where are the eyes pointing, and what does the eye line tell us
39
- about the want?
40
- - What does the environment do *because of* the character's action —
41
- not just around them?
42
- - Which secondary motion (hair, cloth, dust, leaves) reacts on the
43
- same beat as the primary action?
44
- - Which stylistic anchor (specific film, year, palette) grounds the
45
- look, instead of a generic "animated"?
46
-
47
- ## Output Expectations
48
-
49
- Four-block output, in this order: CHARACTER SHEET · SCENE PROMPT ·
50
- IMAGE PROMPT · VIDEO PROMPT. Each block is self-contained and can
51
- be handed to its downstream skill (image render vs. motion prompt)
52
- without rewriting.
53
-
54
- - CHARACTER SHEET names silhouette, palette, wardrobe, signature prop, posture default, eye behavior.
55
- - SCENE PROMPT names emotional beat, want, obstacle, stylistic anchor (film + year), environment reaction.
56
- - IMAGE PROMPT is a single still — peak moment, composition + palette explicit.
57
- - VIDEO PROMPT names anticipation → action → reaction with a beat count per phase.
58
- - Severity vocabulary on review: `must-fix · should-fix · nit`.
59
-
60
- ## Anti-Patterns
61
-
62
- - Do NOT default to neutral expressions. Every beat names a feeling the face is doing.
63
- - Do NOT describe the environment as backdrop. It reacts, or it is not in the prompt.
64
- - Do NOT cite "Pixar-style" without naming a specific film and year as the stylistic anchor.
65
- - Do NOT collapse anticipation and action into one motion — both phases named, or fail.
66
- - Do NOT prescribe lenses — that is the Hollywood director's block.
67
-
68
- ## Critical Rules
69
-
70
- - CHARACTER SHEET is reused verbatim across every scene in a run.
71
- Edits to identity tokens require an explicit revision note.
72
- - SCENE PROMPT names exactly one emotional beat. Compound beats
73
- ("sad but hopeful and tired") fail review.
74
- - VIDEO PROMPT names a beat count per phase (e.g., "anticipation 0.5s,
75
- action 1.2s, reaction 0.8s"). No vague pacing.
76
- - Stylistic anchor cites a specific film + year. Generic style words
77
- fail.
78
- - Eye line is named in every IMAGE PROMPT.
79
-
80
- ## Workflows
81
-
82
- 1. Read the scene idea once. Name the want and the obstacle in one
83
- sentence each.
84
- 2. Choose the stylistic anchor — specific film + year. Justify in
85
- one sentence what it brings.
86
- 3. Draft the CHARACTER SHEET; lock identity tokens.
87
- 4. Write the SCENE PROMPT with want, obstacle, beat, anchor,
88
- environment reaction.
89
- 5. Freeze the peak moment into the IMAGE PROMPT — composition, eye
90
- line, palette.
91
- 6. Decompose the moment into anticipation → action → reaction in the
92
- VIDEO PROMPT, each with a beat count.
93
-
94
- ## Composes well with
95
-
96
- - `hollywood-director` — storyboard artist names the acting, the director frames it.
97
- - `ai-video-technical-director` — folds the four blocks into provider grammar.
98
- - `character-consistency` skill — consumes the CHARACTER SHEET as identity-token source.
@@ -1,20 +0,0 @@
1
- ---
2
- type: "auto"
3
- tier: "2a"
4
- description: "Reading, creating, or updating agent documentation, module docs, roadmaps, or AGENTS.md"
5
- source: package
6
- triggers:
7
- - path_prefix: "agents/"
8
- - path_prefix: ".github/copilot-instructions"
9
- - keyword: "AGENTS.md"
10
- - keyword: "roadmap"
11
- routes_to:
12
- - "skill:agent-docs-writing"
13
- ---
14
-
15
- # Agent Docs
16
-
17
- **Iron Law.** Read agent docs (`AGENTS.md`, `agents/`, module `agents/`) before work; update them after structural changes.
18
-
19
- Body migrated to `skill:agent-docs-writing` (per P4 of `road-to-kernel-and-router.md`).
20
- Trigger-set above activates this routing under the `balanced` and `full` profiles.
@@ -1,23 +0,0 @@
1
- ---
2
- type: "auto"
3
- tier: "mechanical-already"
4
- description: "Editing or creating files inside .augment/ directory — skills, rules, commands, templates, contexts must be project-agnostic"
5
- source: package
6
- triggers:
7
- - path_prefix: ".augment/"
8
- - path_prefix: ".agent-src.uncompressed/"
9
- - keyword: "portable"
10
- routes_to:
11
- - "guideline:augment-portability-patterns"
12
- validator_ignore:
13
- - type: "substring"
14
- pattern: ".agent-src.uncompressed/"
15
- reason: "Rule scopes the portability gate to the uncompressed authoring tree."
16
- ---
17
-
18
- # Augment Portability
19
-
20
- **Iron Law.** Files inside `.augment/` and `.agent-src.uncompressed/` MUST stay project-agnostic — no project names, domains, stacks.
21
-
22
- Body migrated to `guideline:augment-portability-patterns` (per P4 of `road-to-kernel-and-router.md`).
23
- Trigger-set above activates this routing under the `balanced` and `full` profiles.