@event4u/agent-config 1.21.0 → 1.23.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 (130) hide show
  1. package/.agent-src/commands/agents/cleanup.md +31 -17
  2. package/.agent-src/commands/bug-fix.md +1 -0
  3. package/.agent-src/commands/bug-investigate.md +1 -0
  4. package/.agent-src/commands/challenge-me/vision.md +348 -0
  5. package/.agent-src/commands/challenge-me/with-docs.md +333 -0
  6. package/.agent-src/commands/challenge-me.md +61 -0
  7. package/.agent-src/commands/commit/in-chunks.md +30 -10
  8. package/.agent-src/commands/commit.md +46 -6
  9. package/.agent-src/commands/compress.md +19 -13
  10. package/.agent-src/commands/cost-report.md +120 -0
  11. package/.agent-src/commands/council/default.md +64 -17
  12. package/.agent-src/commands/create-pr/description-only.md +8 -0
  13. package/.agent-src/commands/create-pr.md +99 -80
  14. package/.agent-src/commands/feature/plan.md +13 -7
  15. package/.agent-src/commands/grill-me.md +38 -0
  16. package/.agent-src/commands/judge/steps.md +1 -1
  17. package/.agent-src/commands/memory/add.md +16 -8
  18. package/.agent-src/commands/memory/promote.md +17 -9
  19. package/.agent-src/commands/optimize/rtk.md +16 -11
  20. package/.agent-src/commands/prepare-for-review.md +12 -6
  21. package/.agent-src/commands/project-analyze.md +31 -20
  22. package/.agent-src/commands/review-changes.md +24 -15
  23. package/.agent-src/commands/roadmap/ai-council.md +183 -0
  24. package/.agent-src/commands/roadmap/create.md +20 -10
  25. package/.agent-src/commands/roadmap/process-full.md +58 -0
  26. package/.agent-src/commands/roadmap/process-phase.md +69 -0
  27. package/.agent-src/commands/roadmap/process-step.md +57 -0
  28. package/.agent-src/commands/roadmap.md +44 -16
  29. package/.agent-src/commands/threat-model.md +1 -0
  30. package/.agent-src/contexts/augment-infrastructure.md +1 -1
  31. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +53 -18
  32. package/.agent-src/contexts/contracts/frugality-charter.md +57 -0
  33. package/.agent-src/contexts/execution/roadmap-process-loop.md +125 -0
  34. package/.agent-src/contexts/skills-and-commands.md +1 -1
  35. package/.agent-src/rules/architecture.md +9 -0
  36. package/.agent-src/rules/ask-when-uncertain.md +3 -13
  37. package/.agent-src/rules/caveman-speak.md +78 -0
  38. package/.agent-src/rules/direct-answers.md +5 -14
  39. package/.agent-src/rules/improve-before-implement.md +1 -0
  40. package/.agent-src/rules/invite-challenge.md +71 -0
  41. package/.agent-src/rules/markdown-safe-codeblocks.md +6 -7
  42. package/.agent-src/rules/no-cheap-questions.md +4 -14
  43. package/.agent-src/rules/token-efficiency.md +5 -7
  44. package/.agent-src/skills/adr-create/SKILL.md +197 -0
  45. package/.agent-src/skills/adversarial-review/SKILL.md +1 -0
  46. package/.agent-src/skills/agent-docs-writing/SKILL.md +23 -1
  47. package/.agent-src/skills/ai-council/SKILL.md +132 -8
  48. package/.agent-src/skills/bug-analyzer/SKILL.md +1 -0
  49. package/.agent-src/skills/command-writing/SKILL.md +23 -0
  50. package/.agent-src/skills/context-authoring/SKILL.md +23 -0
  51. package/.agent-src/skills/conventional-commits-writing/SKILL.md +23 -0
  52. package/.agent-src/skills/guideline-writing/SKILL.md +22 -0
  53. package/.agent-src/skills/persona-writing/SKILL.md +153 -0
  54. package/.agent-src/skills/readme-writing/SKILL.md +20 -0
  55. package/.agent-src/skills/readme-writing-package/SKILL.md +19 -0
  56. package/.agent-src/skills/roadmap-management/SKILL.md +7 -7
  57. package/.agent-src/skills/roadmap-writing/SKILL.md +157 -0
  58. package/.agent-src/skills/rule-writing/SKILL.md +22 -0
  59. package/.agent-src/skills/script-writing/SKILL.md +226 -0
  60. package/.agent-src/skills/skill-writing/SKILL.md +23 -0
  61. package/.agent-src/skills/systematic-debugging/SKILL.md +22 -2
  62. package/.agent-src/skills/technical-specification/SKILL.md +58 -1
  63. package/.agent-src/skills/test-driven-development/SKILL.md +24 -0
  64. package/.agent-src/skills/threat-modeling/SKILL.md +1 -0
  65. package/.agent-src/templates/agent-settings.md +87 -3
  66. package/.agent-src/templates/command.md +30 -9
  67. package/.agent-src/templates/roadmaps.md +10 -2
  68. package/.agent-src/templates/rule.md +8 -0
  69. package/.agent-src/templates/skill.md +49 -0
  70. package/.claude-plugin/marketplace.json +14 -2
  71. package/AGENTS.md +3 -3
  72. package/CHANGELOG.md +73 -0
  73. package/README.md +5 -5
  74. package/config/agent-settings.template.yml +22 -0
  75. package/docs/architecture.md +4 -4
  76. package/docs/contracts/command-clusters.md +45 -1
  77. package/docs/customization.md +72 -0
  78. package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +126 -0
  79. package/docs/decisions/INDEX.md +15 -0
  80. package/docs/getting-started.md +2 -2
  81. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +27 -19
  82. package/docs/guidelines/agent-infra/carve-out-predicates.md +17 -0
  83. package/docs/guidelines/agent-infra/mcp-request-signing.md +199 -0
  84. package/docs/guidelines/agent-infra/naming.md +1 -1
  85. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +11 -4
  86. package/package.json +1 -1
  87. package/scripts/_lib/__init__.py +5 -0
  88. package/scripts/_lib/script_output.py +140 -0
  89. package/scripts/_phase2_shim_helper.py +1 -1
  90. package/scripts/adr/regenerate_index.py +79 -0
  91. package/scripts/ai_council/one_off_archive/2026-05/_one_off_add_quiet.py +149 -0
  92. package/scripts/ai_council/one_off_archive/2026-05/_one_off_inject_quiet_flag.py +33 -0
  93. package/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_v2.sh +36 -0
  94. package/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_verbosity.sh +26 -0
  95. package/scripts/ai_council/one_off_archive/2026-05/_one_off_per_task.sh +41 -0
  96. package/scripts/ai_council/one_off_archive/2026-05/_one_off_silent_taskfiles.py +98 -0
  97. package/scripts/check_augmentignore.py +4 -1
  98. package/scripts/check_command_count_messaging.py +4 -1
  99. package/scripts/check_compressed_paths.py +4 -1
  100. package/scripts/check_council_layout.py +4 -1
  101. package/scripts/check_council_references.py +4 -1
  102. package/scripts/check_iron_law_prominence.py +3 -1
  103. package/scripts/check_md_language.py +3 -1
  104. package/scripts/check_memory_proposal.py +3 -1
  105. package/scripts/check_public_catalog_links.py +4 -1
  106. package/scripts/check_reply_consistency.py +8 -2
  107. package/scripts/check_roadmap_trackable.py +4 -1
  108. package/scripts/compile_router.py +27 -0
  109. package/scripts/compress.py +33 -19
  110. package/scripts/cost/budget.mjs +152 -0
  111. package/scripts/cost/track.mjs +144 -0
  112. package/scripts/council_cli.py +127 -10
  113. package/scripts/first-run.sh +3 -9
  114. package/scripts/install-hooks.sh +19 -1
  115. package/scripts/install.py +17 -12
  116. package/scripts/install.sh +19 -8
  117. package/scripts/lint_examples.py +6 -2
  118. package/scripts/lint_handoffs.py +4 -1
  119. package/scripts/lint_load_context.py +4 -1
  120. package/scripts/lint_roadmap_complexity.py +6 -2
  121. package/scripts/lint_rule_interactions.py +4 -1
  122. package/scripts/lint_rule_tiers.py +4 -1
  123. package/scripts/measure_frugality_savings.py +164 -0
  124. package/scripts/migrate_command_suggestions.py +2 -2
  125. package/scripts/runtime_dispatcher.py +11 -0
  126. package/scripts/schemas/command.schema.json +5 -0
  127. package/scripts/schemas/rule.schema.json +5 -0
  128. package/scripts/schemas/skill.schema.json +5 -0
  129. package/scripts/skill_linter.py +208 -3
  130. package/.agent-src/commands/roadmap/execute.md +0 -109
@@ -0,0 +1,36 @@
1
+ #!/bin/bash
2
+ # Phase 10.7 baseline — runs only verbosity-aware patched-script tasks.
3
+ # Skips broken-on-dirty-tree tasks (consistency, check-index, validate-schema).
4
+ # This subset is what actually demonstrates the --quiet effect.
5
+ TASKS="check-compressed-paths check-refs check-portability lint-roadmap-complexity check-public-catalog-links check-command-count check-cluster-patterns lint-rule-interactions lint-load-context check-context-paths check-no-roadmap-refs check-council-references lint-one-off-age check-reply-consistency check-iron-law-prominence check-always-budget check-one-off-location lint-rule-budget lint-skills lint-rule-tiers lint-handoffs lint-marketplace lint-examples"
6
+
7
+ run() {
8
+ local label=$1
9
+ local level=$2
10
+ local out=$3
11
+ AGENT_SCRIPT_VERBOSITY=$level task $TASKS > "$out" 2>&1
12
+ local lines=$(wc -l < "$out" | tr -d ' ')
13
+ local chars=$(wc -c < "$out" | tr -d ' ')
14
+ echo "$label: lines=$lines chars=$chars"
15
+ }
16
+
17
+ echo "=== MINIMAL ==="
18
+ run "MINIMAL" minimal /tmp/ci-min.log
19
+ echo ""
20
+ echo "=== VERBOSE ==="
21
+ run "VERBOSE" verbose /tmp/ci-vrb.log
22
+
23
+ ML=$(wc -l < /tmp/ci-min.log | tr -d ' ')
24
+ MC=$(wc -c < /tmp/ci-min.log | tr -d ' ')
25
+ VL=$(wc -l < /tmp/ci-vrb.log | tr -d ' ')
26
+ VC=$(wc -c < /tmp/ci-vrb.log | tr -d ' ')
27
+
28
+ echo ""
29
+ python3 -c "
30
+ ml=$ML; vl=$VL; mc=$MC; vc=$VC
31
+ dl=(vl-ml)/vl*100 if vl else 0
32
+ dc=(vc-mc)/vc*100 if vc else 0
33
+ print(f'Lines: {ml} -> {vl}, reduction={dl:.1f}% (target >=40%)')
34
+ print(f'Chars: {mc} -> {vc}, reduction={dc:.1f}%')
35
+ print('verdict:', 'MET' if dl >= 40 else f'MISSED ({dl:.1f}% < 40%)')
36
+ "
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # Phase 10.7 baseline measurement: post-consistency task ci subset.
3
+ TASKS="counts-check check-index check-router check-compression check-compressed-paths check-refs check-token-optimizer-freshness check-portability check-examples-shape lint-roadmap-complexity check-public-links check-public-catalog-links check-command-count lint-no-new-atomic-commands check-cluster-patterns lint-rule-interactions lint-load-context check-context-paths check-no-roadmap-refs check-council-references lint-one-off-age check-ownership-matrix check-reply-consistency check-iron-law-prominence check-always-budget check-one-off-location validate-schema lint-rule-budget lint-skills lint-rule-tiers lint-handoffs lint-hook-manifest lint-showcase-sessions lint-marketplace"
4
+
5
+ echo "=== MINIMAL ==="
6
+ AGENT_SCRIPT_VERBOSITY=minimal task $TASKS 2>&1 > /tmp/ci-min.log
7
+ ML=$(wc -l < /tmp/ci-min.log | tr -d ' ')
8
+ MC=$(wc -c < /tmp/ci-min.log | tr -d ' ')
9
+ echo "MINIMAL: lines=$ML chars=$MC"
10
+
11
+ echo ""
12
+ echo "=== VERBOSE ==="
13
+ AGENT_SCRIPT_VERBOSITY=verbose task $TASKS 2>&1 > /tmp/ci-vrb.log
14
+ VL=$(wc -l < /tmp/ci-vrb.log | tr -d ' ')
15
+ VC=$(wc -c < /tmp/ci-vrb.log | tr -d ' ')
16
+ echo "VERBOSE: lines=$VL chars=$VC"
17
+
18
+ echo ""
19
+ python3 -c "
20
+ ml=$ML; vl=$VL; mc=$MC; vc=$VC
21
+ dl=(vl-ml)/vl*100 if vl else 0
22
+ dc=(vc-mc)/vc*100 if vc else 0
23
+ print(f'Lines: {ml} -> {vl}, reduction={dl:.1f}% (target >=40%)')
24
+ print(f'Chars: {mc} -> {vc}, reduction={dc:.1f}%')
25
+ print('verdict:', 'MET' if dl >= 40 else f'MISSED ({dl:.1f}% < 40%)')
26
+ "
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ TASKS=(
3
+ check-compressed-paths
4
+ check-refs
5
+ check-portability
6
+ lint-roadmap-complexity
7
+ check-public-catalog-links
8
+ check-command-count
9
+ check-cluster-patterns
10
+ lint-rule-interactions
11
+ lint-load-context
12
+ check-context-paths
13
+ check-no-roadmap-refs
14
+ check-council-references
15
+ lint-one-off-age
16
+ check-reply-consistency
17
+ check-iron-law-prominence
18
+ check-always-budget
19
+ check-one-off-location
20
+ lint-rule-budget
21
+ lint-skills
22
+ lint-rule-tiers
23
+ lint-handoffs
24
+ lint-marketplace
25
+ check-examples-shape
26
+ )
27
+ totalmin=0
28
+ totalvrb=0
29
+ totaldelta=0
30
+ for t in "${TASKS[@]}"; do
31
+ m=$(AGENT_SCRIPT_VERBOSITY=minimal task "$t" 2>&1 | wc -l | tr -d ' ')
32
+ v=$(AGENT_SCRIPT_VERBOSITY=verbose task "$t" 2>&1 | wc -l | tr -d ' ')
33
+ d=$((v - m))
34
+ totalmin=$((totalmin + m))
35
+ totalvrb=$((totalvrb + v))
36
+ totaldelta=$((totaldelta + d))
37
+ printf "%-35s min=%-5s vrb=%-5s d=%s\n" "$t" "$m" "$v" "$d"
38
+ done
39
+ echo ""
40
+ echo "TOTAL: min=$totalmin vrb=$totalvrb delta=$totaldelta"
41
+ python3 -c "print(f'reduction: {($totalvrb - $totalmin)/$totalvrb*100:.1f}%' if $totalvrb else '')"
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env python3
2
+ """One-off (Phase 10.3) — add `silent: true` to safe Taskfile tasks.
3
+
4
+ Inserts a ` silent: true` line directly after each ` <taskname>:` opener,
5
+ unless the task is in CARVE_OUTS or the line already exists.
6
+
7
+ Carve-outs stay loud:
8
+ - install / install-hooks / first-run / install-anthropic-key /
9
+ install-openai-key / setup-evals / test-triggers-live
10
+ - runtime-e2e (per roadmap explicit list)
11
+ - all release* tasks (release.yml — file-level skip)
12
+ - _ci-start / _ci-end / ci (root Taskfile orchestration)
13
+
14
+ Idempotent — running twice is a no-op.
15
+
16
+ Lifecycle: archive after Phase 10.3 lands per one-off-script-lifecycle.md.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import re
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ ROOT = Path(__file__).resolve().parent.parent
25
+
26
+ CARVE_OUTS = {
27
+ "install",
28
+ "install-hooks",
29
+ "first-run",
30
+ "install-anthropic-key",
31
+ "install-openai-key",
32
+ "setup-evals",
33
+ "test-triggers-live",
34
+ "runtime-e2e",
35
+ }
36
+
37
+ # Regex matches a top-level task opener: 2 spaces + name + colon + EOL.
38
+ TASK_OPENER_RE = re.compile(r"^ ([a-z_][a-z0-9_:.-]*):$")
39
+
40
+
41
+ def patch_file(path: Path, skip_all: bool = False) -> tuple[int, int]:
42
+ """Insert ` silent: true` after each safe task opener.
43
+
44
+ Returns (added, skipped).
45
+ """
46
+ if skip_all:
47
+ return (0, 0)
48
+
49
+ text = path.read_text()
50
+ lines = text.splitlines(keepends=False)
51
+ out: list[str] = []
52
+ added = 0
53
+ skipped = 0
54
+ i = 0
55
+ while i < len(lines):
56
+ line = lines[i]
57
+ out.append(line)
58
+ m = TASK_OPENER_RE.match(line)
59
+ if m:
60
+ name = m.group(1)
61
+ # Look ahead one line — already silent?
62
+ next_line = lines[i + 1] if i + 1 < len(lines) else ""
63
+ already = next_line.strip() == "silent: true"
64
+ if name in CARVE_OUTS:
65
+ skipped += 1
66
+ elif already:
67
+ pass # idempotent
68
+ else:
69
+ out.append(" silent: true")
70
+ added += 1
71
+ i += 1
72
+ new_text = "\n".join(out) + ("\n" if text.endswith("\n") else "")
73
+ if new_text != text:
74
+ path.write_text(new_text)
75
+ return (added, skipped)
76
+
77
+
78
+ def main() -> int:
79
+ targets = [
80
+ (ROOT / "taskfiles" / "content.yml", False),
81
+ (ROOT / "taskfiles" / "ci-fast.yml", False),
82
+ (ROOT / "taskfiles" / "engine.yml", False),
83
+ (ROOT / "taskfiles" / "release.yml", True), # all release* loud
84
+ ]
85
+ total_added = 0
86
+ total_skipped = 0
87
+ for path, skip_all in targets:
88
+ added, skipped = patch_file(path, skip_all=skip_all)
89
+ rel = path.relative_to(ROOT)
90
+ print(f" {rel}: +{added} silent · {skipped} carved-out")
91
+ total_added += added
92
+ total_skipped += skipped
93
+ print(f"\n total: +{total_added} silent · {total_skipped} carved-out")
94
+ return 0
95
+
96
+
97
+ if __name__ == "__main__":
98
+ sys.exit(main())
@@ -20,6 +20,8 @@ import sys
20
20
  import time
21
21
  from pathlib import Path
22
22
 
23
+ QUIET = "--quiet" in sys.argv
24
+
23
25
  STALE_DAYS = 90
24
26
  MIN_USEFUL_LINES = 5
25
27
  REPO_ROOT = Path(__file__).resolve().parent.parent
@@ -57,7 +59,8 @@ def check() -> int:
57
59
 
58
60
  def _emit(notes: list[str]) -> None:
59
61
  if not notes:
60
- print("✅ .augmentignore advisory: nothing to suggest.")
62
+ if not QUIET:
63
+ print("✅ .augmentignore advisory: nothing to suggest.")
61
64
  return
62
65
  print("📒 .augmentignore advisory (non-blocking):")
63
66
  for n in notes:
@@ -38,6 +38,8 @@ import re
38
38
  import sys
39
39
  from pathlib import Path
40
40
 
41
+ QUIET = "--quiet" in sys.argv
42
+
41
43
  ROOT = Path(__file__).resolve().parent.parent
42
44
  COMMANDS_DIR = ROOT / ".agent-src.uncompressed" / "commands"
43
45
  README = ROOT / "README.md"
@@ -107,7 +109,8 @@ def main() -> int:
107
109
  errors.append(err)
108
110
 
109
111
  if not errors:
110
- print("✅ All command-count messaging in sync with registry.")
112
+ if not QUIET:
113
+ print("✅ All command-count messaging in sync with registry.")
111
114
  return 0
112
115
 
113
116
  print(f"❌ Command-count messaging drift — {len(errors)} mismatch(es):")
@@ -40,6 +40,8 @@ from pathlib import Path
40
40
 
41
41
  import yaml
42
42
 
43
+ QUIET = "--quiet" in sys.argv
44
+
43
45
  ROOT = Path(__file__).resolve().parent.parent
44
46
  RULES_DIR = ROOT / ".agent-src" / "rules"
45
47
 
@@ -205,7 +207,8 @@ def main() -> int:
205
207
  print(f"\n{len(viols)} violation(s) in .agent-src/rules/")
206
208
  return 1
207
209
  rule_count = len(list(RULES_DIR.glob('*.md')))
208
- print(f"✅ compressed-path check clean ({rule_count} rules, {len(audited)} ignore(s) audited)")
210
+ if not QUIET:
211
+ print(f"✅ compressed-path check clean ({rule_count} rules, {len(audited)} ignore(s) audited)")
209
212
  return 0
210
213
 
211
214
 
@@ -32,6 +32,8 @@ import re
32
32
  import sys
33
33
  from pathlib import Path
34
34
 
35
+ QUIET = "--quiet" in sys.argv
36
+
35
37
  AGENTS_ROOT = Path("agents")
36
38
  CANONICAL_DIRS = {
37
39
  "council-questions": ".md",
@@ -97,7 +99,8 @@ def main() -> int:
97
99
  '§ "Output path convention"'
98
100
  )
99
101
  return 1
100
- print("✅ Council layout clean.")
102
+ if not QUIET:
103
+ print("✅ Council layout clean.")
101
104
  return 0
102
105
 
103
106
 
@@ -34,6 +34,8 @@ import sys
34
34
  from pathlib import Path
35
35
  from typing import Iterable
36
36
 
37
+ QUIET = "--quiet" in sys.argv
38
+
37
39
  ROOT = Path(".")
38
40
 
39
41
  # A specific file inside a council dir: must end with .md or .json,
@@ -124,7 +126,8 @@ def main() -> int:
124
126
  violations.append((path, ln, ref))
125
127
 
126
128
  if not violations:
127
- print("✅ No forbidden council references in durable artefacts.")
129
+ if not QUIET:
130
+ print("✅ No forbidden council references in durable artefacts.")
128
131
  return 0
129
132
 
130
133
  print(f"❌ {len(violations)} forbidden council reference(s):\n")
@@ -111,6 +111,7 @@ def main() -> int:
111
111
  help="Files or directories to scan (default: .agent-src.uncompressed/rules)",
112
112
  )
113
113
  parser.add_argument("--format", choices=["text", "json"], default="text")
114
+ parser.add_argument("--quiet", action="store_true", help="Only print on failure")
114
115
  args = parser.parse_args()
115
116
 
116
117
  targets = _resolve_targets(args.paths)
@@ -125,7 +126,8 @@ def main() -> int:
125
126
  print(json.dumps([asdict(v) for v in all_violations], indent=2, ensure_ascii=False))
126
127
  else:
127
128
  if not all_violations:
128
- print(f"✅ Iron Law prominence clean ({len(targets)} file(s) scanned).")
129
+ if not args.quiet:
130
+ print(f"✅ Iron Law prominence clean ({len(targets)} file(s) scanned).")
129
131
  else:
130
132
  print(f"❌ {len(all_violations)} Iron-Law prominence violation(s):\n")
131
133
  for v in all_violations:
@@ -124,6 +124,7 @@ def main() -> int:
124
124
  parser = argparse.ArgumentParser(description=__doc__)
125
125
  parser.add_argument("paths", nargs="+", help="One or more .md files to scan")
126
126
  parser.add_argument("--format", choices=["text", "json"], default="text")
127
+ parser.add_argument("--quiet", action="store_true", help="Only print on failure")
127
128
  args = parser.parse_args()
128
129
 
129
130
  all_violations: list[Violation] = []
@@ -141,7 +142,8 @@ def main() -> int:
141
142
  print(json.dumps([asdict(v) for v in all_violations], indent=2, ensure_ascii=False))
142
143
  else:
143
144
  if not all_violations:
144
- print("✅ No German content detected.")
145
+ if not args.quiet:
146
+ print("✅ No German content detected.")
145
147
  else:
146
148
  print(f"❌ {len(all_violations)} violation(s) found:\n")
147
149
  for v in all_violations:
@@ -152,6 +152,7 @@ def main() -> int:
152
152
  grp.add_argument("--intake-id", help="Promote an intake record by id")
153
153
  grp.add_argument("--proposal", help="Promote a proposal YAML file")
154
154
  ap.add_argument("--format", choices=["text", "json"], default="text")
155
+ ap.add_argument("--quiet", action="store_true", help="Only print on failure")
155
156
  args = ap.parse_args()
156
157
  if args.intake_id:
157
158
  record = _find_intake(args.intake_id)
@@ -172,7 +173,8 @@ def main() -> int:
172
173
  for f in failures:
173
174
  print(f" 🔴 {f}")
174
175
  else:
175
- print(f"✅ {source} gate passed")
176
+ if not args.quiet:
177
+ print(f"✅ {source} — gate passed")
176
178
  return 1 if failures else 0
177
179
 
178
180
 
@@ -27,6 +27,8 @@ import re
27
27
  import sys
28
28
  from pathlib import Path
29
29
 
30
+ QUIET = "--quiet" in sys.argv
31
+
30
32
  ROOT = Path(__file__).resolve().parent.parent
31
33
  CATALOG = ROOT / "docs" / "catalog.md"
32
34
  PACKAGE_JSON = ROOT / "package.json"
@@ -95,7 +97,8 @@ def main() -> int:
95
97
 
96
98
  total_violations = len(forbidden) + len(missing) + len(unshipped)
97
99
  if not total_violations:
98
- print(f"✅ docs/catalog.md all links resolve to shipped surfaces.")
100
+ if not QUIET:
101
+ print(f"✅ docs/catalog.md — all links resolve to shipped surfaces.")
99
102
  return 0
100
103
 
101
104
  print(f"❌ docs/catalog.md — {total_violations} violation(s):")
@@ -21,6 +21,8 @@ import re
21
21
  import sys
22
22
  from pathlib import Path
23
23
 
24
+ QUIET = "--quiet" in sys.argv
25
+
24
26
  OPTION_LINE_RE = re.compile(r"^\s*>?\s*(\d+)\.\s+\S")
25
27
  REC_LINE_RE = re.compile(
26
28
  r"(?:Recommendation|Empfehlung)\s*:\s*(\d+)\b", re.IGNORECASE
@@ -108,7 +110,8 @@ def cmd_scan_dir(root: Path) -> int:
108
110
  print(f" 🔴 {path}:{line} — inline-tag — {snippet}", file=sys.stderr)
109
111
  print(f"\n❌ {len(violations)} legacy-pattern violation(s)", file=sys.stderr)
110
112
  return 6
111
- print(f"✅ No legacy (recommended) tags found under {root}")
113
+ if not QUIET:
114
+ print(f"✅ No legacy (recommended) tags found under {root}")
112
115
  return 0
113
116
 
114
117
 
@@ -121,6 +124,8 @@ def main(argv: list[str] | None = None) -> int:
121
124
  p.add_argument("--strict", action="store_true",
122
125
  help="numbered options REQUIRE recommendation line (rule 5)")
123
126
  p.add_argument("-v", "--verbose", action="store_true")
127
+ p.add_argument("--quiet", action="store_true",
128
+ help="suppress success messages (P10.5)")
124
129
  args = p.parse_args(argv)
125
130
 
126
131
  if args.scan_dir:
@@ -130,7 +135,8 @@ def main(argv: list[str] | None = None) -> int:
130
135
  code, msg = validate(text, strict=args.strict)
131
136
  if code == 0:
132
137
  if args.verbose:
133
- print(f"✅ {msg}")
138
+ if not QUIET:
139
+ print(f"✅ {msg}")
134
140
  return 0
135
141
  print(f"❌ [exit {code}] {msg}", file=sys.stderr)
136
142
  return code
@@ -43,6 +43,8 @@ from update_roadmap_progress import ( # noqa: E402
43
43
  parse_frontmatter,
44
44
  )
45
45
 
46
+ QUIET = "--quiet" in sys.argv
47
+
46
48
  ROADMAP_ROOT = Path("agents/roadmaps")
47
49
 
48
50
 
@@ -103,7 +105,8 @@ def main() -> int:
103
105
  )
104
106
  return 1
105
107
  count = len(find_active_roadmaps(ROADMAP_ROOT))
106
- print(f"✅ {count} active roadmap(s) — all parseable, all phases have checkboxes.")
108
+ if not QUIET:
109
+ print(f"✅ {count} active roadmap(s) — all parseable, all phases have checkboxes.")
107
110
  return 0
108
111
 
109
112
 
@@ -17,8 +17,18 @@ from pathlib import Path
17
17
  ROOT = Path(__file__).resolve().parent.parent
18
18
  RULES_DIR = ROOT / ".agent-src.uncompressed" / "rules"
19
19
  OUT_PATH = ROOT / "router.json"
20
+ SETTINGS_PATH = ROOT / ".agent-settings.yml"
20
21
  SCHEMA_VERSION = 1
21
22
 
23
+ # Compile-time rule toggles. Maps rule-id → settings predicate.
24
+ # Rule omitted from router.json when predicate returns False.
25
+ # Per road-to-token-frugality § Phase 8.2 — caveman.speak compile-time toggle.
26
+ COMPILE_TIME_TOGGLES = {
27
+ "caveman-speak": lambda s: bool(
28
+ s.get("caveman", {}).get("enabled", True)
29
+ ) and bool(s.get("caveman", {}).get("speak", True)),
30
+ }
31
+
22
32
  # Maps legacy tier values to the router-canonical names. See
23
33
  # docs/contracts/rule-router.md § Backward compatibility.
24
34
  LEGACY_TIER_MAP = {
@@ -89,7 +99,21 @@ def _normalize_trigger(item) -> dict | None:
89
99
  return {keys[0]: str(item[keys[0]])}
90
100
 
91
101
 
102
+ def _load_settings() -> dict:
103
+ """Read .agent-settings.yml for compile-time toggles. Stdlib-only fallback."""
104
+ if not SETTINGS_PATH.exists():
105
+ return {}
106
+ text = SETTINGS_PATH.read_text(encoding="utf-8")
107
+ try:
108
+ import yaml # type: ignore
109
+ data = yaml.safe_load(text) or {}
110
+ return data if isinstance(data, dict) else {}
111
+ except ImportError:
112
+ return {}
113
+
114
+
92
115
  def _collect(rules_dir: Path) -> dict:
116
+ settings = _load_settings()
93
117
  kernel: list[str] = []
94
118
  tiered: dict[str, list[dict]] = {"tier-1": [], "tier-2": []}
95
119
  for path in sorted(rules_dir.glob("*.md")):
@@ -97,6 +121,9 @@ def _collect(rules_dir: Path) -> dict:
97
121
  if not fm:
98
122
  continue
99
123
  rule_id = path.stem
124
+ if rule_id in COMPILE_TIME_TOGGLES:
125
+ if not COMPILE_TIME_TOGGLES[rule_id](settings):
126
+ continue
100
127
  rule_type = str(fm.get("type", "auto"))
101
128
  tier = _resolve_tier(rule_type, fm.get("tier", ""))
102
129
  if tier not in ALLOWED_TIERS:
@@ -26,6 +26,9 @@ import shutil
26
26
  import sys
27
27
  from pathlib import Path
28
28
 
29
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
30
+ from _lib.script_output import info, success, flush_summary, resolve_level # noqa: E402
31
+
29
32
  PROJECT_ROOT = Path(__file__).resolve().parent.parent
30
33
  SOURCE_DIR = PROJECT_ROOT / ".agent-src.uncompressed"
31
34
  TARGET_DIR = PROJECT_ROOT / ".agent-src"
@@ -479,11 +482,11 @@ def generate_rule_symlinks() -> int:
479
482
  if tool_count != source_count:
480
483
  print(f" ⚠️ {tool_dir}: {tool_count} rules (expected {source_count})")
481
484
 
482
- print(f" ✅ Created {total} rule symlinks across {len(TOOL_DIRS)} tool directories ({source_count} rules each)")
485
+ info(f" ✅ Created {total} rule symlinks across {len(TOOL_DIRS)} tool directories ({source_count} rules each)")
483
486
  return total
484
487
 
485
488
 
486
- def generate_windsurfrules() -> None:
489
+ def generate_windsurfrules() -> int:
487
490
  """Generate .windsurfrules by concatenating all rules (no frontmatter).
488
491
  """
489
492
  rules = sorted([f.name for f in RULES_SOURCE.glob("*.md")])
@@ -496,7 +499,8 @@ def generate_windsurfrules() -> None:
496
499
 
497
500
  output = PROJECT_ROOT / ".windsurfrules"
498
501
  output.write_text("\n".join(parts) + "\n")
499
- print(f" ✅ Generated .windsurfrules ({len(rules)} rules)")
502
+ info(f" ✅ Generated .windsurfrules ({len(rules)} rules)")
503
+ return len(rules)
500
504
 
501
505
 
502
506
  def generate_gemini_md() -> None:
@@ -505,7 +509,7 @@ def generate_gemini_md() -> None:
505
509
  if link.exists() or link.is_symlink():
506
510
  link.unlink()
507
511
  link.symlink_to("AGENTS.md")
508
- print(" ✅ Created GEMINI.md → AGENTS.md symlink")
512
+ info(" ✅ Created GEMINI.md → AGENTS.md symlink")
509
513
 
510
514
 
511
515
  def _command_slug(source_file: Path) -> str:
@@ -531,12 +535,12 @@ def _iter_commands():
531
535
  yield source_file, _command_slug(source_file)
532
536
 
533
537
 
534
- def generate_claude_skills() -> None:
538
+ def generate_claude_skills() -> int:
535
539
  """Create .claude/skills/ symlinks for ALL skills in .agent-src/skills/.
536
540
  """
537
541
  if not SKILLS_SOURCE.exists():
538
- print(" ⚠️ .agent-src/skills/ not found — skipping skills")
539
- return
542
+ print(" ⚠️ .agent-src/skills/ not found — skipping skills", file=sys.stderr)
543
+ return 0
540
544
 
541
545
  # All skill directories in .agent-src/skills/
542
546
  skills = sorted([d.name for d in SKILLS_SOURCE.iterdir() if d.is_dir()])
@@ -559,7 +563,8 @@ def generate_claude_skills() -> None:
559
563
  link.symlink_to(rel_target)
560
564
  count += 1
561
565
 
562
- print(f" ✅ Created {count} skill symlinks in .claude/skills/")
566
+ info(f" ✅ Created {count} skill symlinks in .claude/skills/")
567
+ return count
563
568
 
564
569
 
565
570
  def extract_description_from_md(content: str) -> str:
@@ -573,7 +578,7 @@ def extract_description_from_md(content: str) -> str:
573
578
  return ""
574
579
 
575
580
 
576
- def generate_claude_commands() -> None:
581
+ def generate_claude_commands() -> int:
577
582
  """Create .claude/skills/{slug}/SKILL.md symlinks for ALL Augment commands.
578
583
 
579
584
  Commands in .agent-src/commands/ are the single source of truth.
@@ -585,8 +590,8 @@ def generate_claude_commands() -> None:
585
590
  to `council-default` so directories never collide in `.claude/skills/`.
586
591
  """
587
592
  if not COMMANDS_SOURCE.exists():
588
- print(" ⚠️ .agent-src/commands/ not found — skipping commands")
589
- return
593
+ print(" ⚠️ .agent-src/commands/ not found — skipping commands", file=sys.stderr)
594
+ return 0
590
595
 
591
596
  CLAUDE_SKILLS_DIR.mkdir(parents=True, exist_ok=True)
592
597
 
@@ -642,7 +647,8 @@ def generate_claude_commands() -> None:
642
647
  msg += f" ({skipped} skipped — same-name skill exists)"
643
648
  if removed_dirs:
644
649
  msg += f" ({removed_dirs} stale dirs removed)"
645
- print(msg)
650
+ info(msg)
651
+ return count
646
652
 
647
653
 
648
654
  def generate_persona_symlinks() -> int:
@@ -676,20 +682,28 @@ def generate_persona_symlinks() -> int:
676
682
  link.symlink_to(target)
677
683
  total += 1
678
684
 
679
- print(f" ✅ Created {total} persona symlinks across {len(PERSONA_TOOL_DIRS)} tool directories ({len(personas)} personas each)")
685
+ info(f" ✅ Created {total} persona symlinks across {len(PERSONA_TOOL_DIRS)} tool directories ({len(personas)} personas each)")
680
686
  return total
681
687
 
682
688
 
683
689
  def generate_tools() -> None:
684
690
  """Generate all tool-specific directories and files."""
685
- print("🔧 Generating multi-agent tool directories...\n")
686
- generate_rule_symlinks()
691
+ info("🔧 Generating multi-agent tool directories...\n")
692
+ rules = generate_rule_symlinks()
687
693
  generate_windsurfrules()
688
694
  generate_gemini_md()
689
- generate_claude_skills()
690
- generate_claude_commands()
691
- generate_persona_symlinks()
692
- print("\n✅ All tool directories generated")
695
+ skills = generate_claude_skills()
696
+ commands = generate_claude_commands()
697
+ personas = generate_persona_symlinks()
698
+ summary = (
699
+ f"✅ generate-tools — rules={rules} skills={skills} "
700
+ f"commands={commands} personas={personas}"
701
+ )
702
+ if resolve_level() == "verbose":
703
+ print(f"\n{summary}")
704
+ else:
705
+ success(summary)
706
+ flush_summary()
693
707
 
694
708
 
695
709
  # ── .augment/ projection ──────────────────────────────────────────────