@event4u/agent-config 1.20.0 → 1.22.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.
- package/.agent-src/commands/agents.md +1 -1
- package/.agent-src/commands/bug-fix.md +2 -1
- package/.agent-src/commands/bug-investigate.md +3 -2
- package/.agent-src/commands/challenge-me/vision.md +348 -0
- package/.agent-src/commands/challenge-me/with-docs.md +333 -0
- package/.agent-src/commands/challenge-me.md +61 -0
- package/.agent-src/commands/chat-history/import.md +60 -64
- package/.agent-src/commands/compress.md +12 -0
- package/.agent-src/commands/context/create.md +2 -2
- package/.agent-src/commands/context.md +1 -1
- package/.agent-src/commands/copilot-agents.md +1 -1
- package/.agent-src/commands/council/default.md +69 -10
- package/.agent-src/commands/council.md +1 -1
- package/.agent-src/commands/create-pr.md +7 -3
- package/.agent-src/commands/e2e-heal.md +1 -1
- package/.agent-src/commands/e2e-plan.md +1 -1
- package/.agent-src/commands/feature/dev.md +3 -3
- package/.agent-src/commands/feature.md +1 -1
- package/.agent-src/commands/fix/seeder.md +2 -2
- package/.agent-src/commands/fix.md +1 -1
- package/.agent-src/commands/grill-me.md +38 -0
- package/.agent-src/commands/jira-ticket.md +1 -1
- package/.agent-src/commands/judge/steps.md +1 -1
- package/.agent-src/commands/judge.md +2 -2
- package/.agent-src/commands/memory.md +1 -1
- package/.agent-src/commands/mode.md +5 -5
- package/.agent-src/commands/module.md +1 -1
- package/.agent-src/commands/onboard.md +4 -4
- package/.agent-src/commands/optimize/augmentignore.md +1 -1
- package/.agent-src/commands/optimize-prompt.md +61 -0
- package/.agent-src/commands/optimize.md +1 -1
- package/.agent-src/commands/override.md +1 -1
- package/.agent-src/commands/review-changes.md +1 -1
- package/.agent-src/commands/review-routing.md +1 -1
- package/.agent-src/commands/roadmap/ai-council.md +183 -0
- package/.agent-src/commands/roadmap/create.md +6 -1
- package/.agent-src/commands/roadmap/process-full.md +58 -0
- package/.agent-src/commands/roadmap/process-phase.md +69 -0
- package/.agent-src/commands/roadmap/process-step.md +57 -0
- package/.agent-src/commands/roadmap.md +45 -17
- package/.agent-src/commands/set-cost-profile.md +3 -3
- package/.agent-src/commands/sync-agent-settings.md +2 -2
- package/.agent-src/commands/tests/create.md +2 -2
- package/.agent-src/commands/tests.md +1 -1
- package/.agent-src/commands/threat-model.md +5 -4
- package/.agent-src/contexts/augment-infrastructure.md +1 -1
- package/.agent-src/contexts/authority/commit-mechanics.md +14 -1
- package/.agent-src/contexts/authority/destructive-mechanics.md +14 -1
- package/.agent-src/contexts/authority/scope-mechanics.md +5 -0
- package/.agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +76 -0
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +54 -19
- package/.agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +98 -0
- package/.agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +93 -0
- package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +128 -5
- package/.agent-src/contexts/execution/autonomy-mechanics.md +44 -0
- package/.agent-src/contexts/execution/roadmap-process-loop.md +125 -0
- package/.agent-src/contexts/model-recommendations.md +2 -2
- package/.agent-src/contexts/override-system.md +1 -1
- package/.agent-src/contexts/skills-and-commands.md +1 -1
- package/.agent-src/personas/product-owner.md +2 -2
- package/.agent-src/personas/qa.md +1 -1
- package/.agent-src/rules/agent-authority.md +5 -6
- package/.agent-src/rules/agent-docs.md +11 -53
- package/.agent-src/rules/analysis-skill-routing.md +10 -40
- package/.agent-src/rules/architecture.md +6 -1
- package/.agent-src/rules/artifact-drafting-protocol.md +5 -0
- package/.agent-src/rules/artifact-engagement-recording.md +23 -59
- package/.agent-src/rules/ask-when-uncertain.md +24 -47
- package/.agent-src/rules/augment-portability.md +14 -62
- package/.agent-src/rules/augment-source-of-truth.md +10 -1
- package/.agent-src/rules/autonomous-execution.md +17 -98
- package/.agent-src/rules/capture-learnings.md +9 -80
- package/.agent-src/rules/cli-output-handling.md +12 -42
- package/.agent-src/rules/command-suggestion-policy.md +25 -73
- package/.agent-src/rules/commit-conventions.md +9 -58
- package/.agent-src/rules/commit-policy.md +16 -47
- package/.agent-src/rules/context-hygiene.md +5 -0
- package/.agent-src/rules/direct-answers.md +21 -50
- package/.agent-src/rules/docker-commands.md +11 -45
- package/.agent-src/rules/docs-sync.md +10 -56
- package/.agent-src/rules/downstream-changes.md +5 -0
- package/.agent-src/rules/e2e-testing.md +9 -44
- package/.agent-src/rules/guidelines.md +13 -75
- package/.agent-src/rules/improve-before-implement.md +11 -2
- package/.agent-src/rules/invite-challenge.md +71 -0
- package/.agent-src/rules/language-and-tone.md +41 -106
- package/.agent-src/rules/laravel-translations.md +11 -40
- package/.agent-src/rules/markdown-safe-codeblocks.md +4 -0
- package/.agent-src/rules/minimal-safe-diff.md +4 -0
- package/.agent-src/rules/missing-tool-handling.md +4 -0
- package/.agent-src/rules/model-recommendation.md +9 -61
- package/.agent-src/rules/no-attribution-footers.md +5 -0
- package/.agent-src/rules/no-cheap-questions.md +11 -27
- package/.agent-src/rules/no-council-references.md +76 -0
- package/.agent-src/rules/no-roadmap-references.md +7 -0
- package/.agent-src/rules/non-destructive-by-default.md +13 -43
- package/.agent-src/rules/onboarding-gate.md +9 -117
- package/.agent-src/rules/package-ci-checks.md +10 -37
- package/.agent-src/rules/php-coding.md +10 -55
- package/.agent-src/rules/preservation-guard.md +9 -0
- package/.agent-src/rules/review-routing-awareness.md +9 -97
- package/.agent-src/rules/reviewer-awareness.md +8 -83
- package/.agent-src/rules/roadmap-progress-sync.md +7 -170
- package/.agent-src/rules/role-mode-adherence.md +6 -2
- package/.agent-src/rules/rule-type-governance.md +8 -66
- package/.agent-src/rules/runtime-safety.md +5 -0
- package/.agent-src/rules/scope-control.md +17 -62
- package/.agent-src/rules/security-sensitive-stop.md +7 -1
- package/.agent-src/rules/size-enforcement.md +6 -1
- package/.agent-src/rules/skill-improvement-trigger.md +9 -49
- package/.agent-src/rules/skill-quality.md +7 -113
- package/.agent-src/rules/slash-command-routing-policy.md +11 -63
- package/.agent-src/rules/think-before-action.md +22 -87
- package/.agent-src/rules/token-efficiency.md +10 -74
- package/.agent-src/rules/token-optimizer-maintenance.md +68 -0
- package/.agent-src/rules/tool-safety.md +4 -0
- package/.agent-src/rules/ui-audit-gate.md +25 -61
- package/.agent-src/rules/upstream-proposal.md +9 -67
- package/.agent-src/rules/user-interaction.md +22 -108
- package/.agent-src/rules/verify-before-complete.md +1 -1
- package/.agent-src/skills/adversarial-review/SKILL.md +1 -0
- package/.agent-src/skills/agent-docs-writing/SKILL.md +1 -1
- package/.agent-src/skills/ai-council/SKILL.md +197 -8
- package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/.agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/.agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/.agent-src/skills/authz-review/SKILL.md +1 -1
- package/.agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/.agent-src/skills/blast-radius-analyzer/SKILL.md +8 -8
- package/.agent-src/skills/bug-analyzer/SKILL.md +6 -5
- package/.agent-src/skills/code-refactoring/SKILL.md +4 -4
- package/.agent-src/skills/code-review/SKILL.md +2 -2
- package/.agent-src/skills/command-writing/SKILL.md +11 -0
- package/.agent-src/skills/composer-packages/SKILL.md +2 -2
- package/.agent-src/skills/context-authoring/SKILL.md +11 -0
- package/.agent-src/skills/context-document/SKILL.md +1 -1
- package/.agent-src/skills/copilot-agents-optimization/SKILL.md +23 -0
- package/.agent-src/skills/copilot-config/SKILL.md +1 -1
- package/.agent-src/skills/dependency-upgrade/SKILL.md +2 -2
- package/.agent-src/skills/devcontainer/SKILL.md +2 -2
- package/.agent-src/skills/developer-like-execution/SKILL.md +1 -1
- package/.agent-src/skills/docker/SKILL.md +1 -1
- package/.agent-src/skills/dto-creator/SKILL.md +1 -1
- package/.agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/.agent-src/skills/fe-design/SKILL.md +4 -4
- package/.agent-src/skills/feature-planning/SKILL.md +5 -5
- package/.agent-src/skills/funnel-analysis/SKILL.md +1 -1
- package/.agent-src/skills/laravel/SKILL.md +1 -1
- package/.agent-src/skills/laravel-notifications/SKILL.md +5 -5
- package/.agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/.agent-src/skills/laravel-pulse/SKILL.md +4 -4
- package/.agent-src/skills/laravel-reverb/SKILL.md +2 -2
- package/.agent-src/skills/laravel-scheduling/SKILL.md +1 -1
- package/.agent-src/skills/migration-creator/SKILL.md +7 -7
- package/.agent-src/skills/multi-tenancy/SKILL.md +8 -8
- package/.agent-src/skills/performance-analysis/SKILL.md +3 -3
- package/.agent-src/skills/pest-testing/SKILL.md +6 -6
- package/.agent-src/skills/php-service/SKILL.md +2 -2
- package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/.agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/.agent-src/skills/project-analyzer/SKILL.md +4 -4
- package/.agent-src/skills/prompt-optimizer/SKILL.md +108 -0
- package/.agent-src/skills/readme-reviewer/SKILL.md +1 -1
- package/.agent-src/skills/roadmap-management/SKILL.md +7 -7
- package/.agent-src/skills/rule-writing/SKILL.md +33 -0
- package/.agent-src/skills/sentry-integration/SKILL.md +1 -1
- package/.agent-src/skills/skill-writing/SKILL.md +14 -0
- package/.agent-src/skills/systematic-debugging/SKILL.md +22 -2
- package/.agent-src/skills/technical-specification/SKILL.md +58 -1
- package/.agent-src/skills/terraform/SKILL.md +2 -2
- package/.agent-src/skills/terragrunt/SKILL.md +8 -8
- package/.agent-src/skills/test-performance/SKILL.md +5 -5
- package/.agent-src/skills/threat-modeling/SKILL.md +3 -2
- package/.agent-src/skills/token-optimizer/SKILL.md +110 -0
- package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/.agent-src/templates/AGENTS.md +1 -1
- package/.agent-src/templates/agent-settings.md +35 -19
- package/.agent-src/templates/command.md +17 -1
- package/.agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/.agent-src/templates/contexts.md +1 -1
- package/.agent-src/templates/copilot-instructions.md +21 -0
- package/.agent-src/templates/copilot-review-instructions.md +76 -0
- package/.agent-src/templates/features.md +1 -1
- package/.agent-src/templates/roadmaps.md +10 -2
- package/.agent-src/templates/rule.md +129 -0
- package/.agent-src/templates/skill.md +17 -0
- package/.claude-plugin/marketplace.json +12 -2
- package/AGENTS.md +32 -5
- package/CHANGELOG.md +107 -3
- package/README.md +22 -21
- package/config/agent-settings.template.yml +66 -10
- package/config/gitignore-block.txt +7 -0
- package/docs/architecture.md +86 -5
- package/docs/catalog.md +16 -6
- package/docs/contracts/agent-memory-contract.md +1 -1
- package/docs/contracts/command-clusters.md +45 -1
- package/docs/contracts/context-paths.md +2 -1
- package/docs/contracts/file-ownership-matrix.json +354 -500
- package/docs/contracts/iron-law-overrides.txt +25 -0
- package/docs/contracts/kernel-membership.md +273 -0
- package/docs/contracts/load-context-schema.md +26 -11
- package/docs/contracts/pilot/agent-authority.md +24 -0
- package/docs/contracts/pilot/direct-answers.md +70 -0
- package/docs/contracts/pilot/language-and-tone.md +63 -0
- package/docs/contracts/rule-classification.md +170 -0
- package/docs/contracts/rule-router.md +153 -0
- package/docs/customization.md +17 -6
- package/docs/decisions/ADR-001-kernel-swap-deferred.md +109 -0
- package/docs/decisions/ADR-002-kernel-bucket-overrides.md +124 -0
- package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +126 -0
- package/docs/decisions/ADR-rule-kernel-and-router.md +122 -0
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +176 -0
- package/docs/guidelines/agent-infra/rule-type-governance.md +73 -0
- package/docs/guidelines/agent-infra/size-and-scope.md +13 -2
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +119 -0
- package/docs/guidelines/augment-portability-patterns.md +68 -0
- package/docs/guidelines/php/php-coding-patterns.md +62 -0
- package/package.json +1 -1
- package/scripts/_p43_bodies.py +235 -0
- package/scripts/_p43_compress.py +118 -0
- package/scripts/_p4_migrate.py +199 -0
- package/scripts/_phase2_shim_helper.py +1 -1
- package/scripts/_pilot_council_question.py +57 -0
- package/scripts/_pilot_measure.py +53 -0
- package/scripts/ai_council/session.py +107 -5
- package/scripts/build_linear_digest.py +3 -5
- package/scripts/check_always_budget.py +39 -6
- package/scripts/check_compressed_paths.py +213 -0
- package/scripts/check_compression.py +15 -0
- package/scripts/check_context_paths.py +1 -0
- package/scripts/check_council_layout.py +105 -0
- package/scripts/check_council_references.py +145 -0
- package/scripts/check_portability.py +2 -0
- package/scripts/check_references.py +2 -0
- package/scripts/check_token_optimizer_freshness.py +131 -0
- package/scripts/compile_router.py +148 -0
- package/scripts/compress.py +219 -11
- package/scripts/council_cli.py +132 -11
- package/scripts/council_prune.py +81 -0
- package/scripts/count_token_optimizer_usage.sh +54 -0
- package/scripts/install.sh +44 -2
- package/scripts/iron_law_sha.py +98 -0
- package/scripts/lint_load_context.py +35 -5
- package/scripts/measure_rule_budget.py +314 -0
- package/scripts/migrate_command_suggestions.py +2 -2
- package/scripts/prototype_lint_contradictions.py +150 -0
- package/scripts/schemas/command.schema.json +5 -0
- package/scripts/schemas/rule.schema.json +60 -6
- package/scripts/schemas/skill.schema.json +5 -0
- package/scripts/skill_linter.py +197 -7
- package/scripts/smoke_path_resolution.py +93 -0
- package/scripts/validate_frontmatter.py +41 -1
- package/.agent-src/commands/roadmap/execute.md +0 -109
- package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +0 -72
- package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +0 -79
- package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +0 -87
- package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +0 -62
- package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +0 -85
- package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +0 -65
- package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +0 -53
- /package/{docs → .agent-src/contexts}/contracts/artifact-engagement-flow.md +0 -0
- /package/{docs → .agent-src/contexts}/contracts/command-suggestion-flow.md +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Measure rule-bucket char counts (kernel + auto) for the rule-kernel roadmap.
|
|
3
|
+
|
|
4
|
+
Source of truth: `.agent-src.uncompressed/rules/*.md`. Frontmatter (YAML
|
|
5
|
+
between two `---` lines at file start) is stripped before counting; only
|
|
6
|
+
the rule body counts toward the bucket.
|
|
7
|
+
|
|
8
|
+
Buckets follow the existing frontmatter `type:` field:
|
|
9
|
+
- `always` rules → always-bucket (today's kernel proxy).
|
|
10
|
+
- `auto` rules → auto-bucket.
|
|
11
|
+
|
|
12
|
+
Output:
|
|
13
|
+
- Default: stdout table (per-rule rows, top-5 oversize, totals).
|
|
14
|
+
- `--json`: deterministic JSON (sorted keys, sorted lists).
|
|
15
|
+
|
|
16
|
+
Acceptance per `road-to-kernel-and-router.md` P1.1: re-runnable,
|
|
17
|
+
deterministic, stdlib-only, no network.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import datetime as _dt
|
|
24
|
+
import json
|
|
25
|
+
import sys
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
29
|
+
RULES_DIR = REPO_ROOT / ".agent-src.uncompressed" / "rules"
|
|
30
|
+
OVERRIDES_FILE = REPO_ROOT / "docs" / "contracts" / "iron-law-overrides.txt"
|
|
31
|
+
TREND_FILE = REPO_ROOT / "agents" / ".rule-budget-history.jsonl"
|
|
32
|
+
|
|
33
|
+
# Council R2 amendments (2026-05-06) — see docs/contracts/kernel-membership.md § 5.1.
|
|
34
|
+
# Per-rule cap raised 1.5k → 2.5k; warning band raised 1.2k → 2.0k.
|
|
35
|
+
# ADR-002 (2026-05-06) — KERNEL_HARD raised 25k → 26k after empirical r_actual=0.795
|
|
36
|
+
# vs r_projected=0.712; see docs/decisions/ADR-002-kernel-bucket-overrides.md.
|
|
37
|
+
KERNEL_HARD = 26_000
|
|
38
|
+
KERNEL_TARGET = 20_000
|
|
39
|
+
PER_RULE_HARD = 2_500
|
|
40
|
+
PER_RULE_TARGET = 2_000
|
|
41
|
+
PER_RULE_OVERRIDE_CEILING = 4_000 # Iron-Law-override ADR ceiling.
|
|
42
|
+
|
|
43
|
+
# Locked kernel set — docs/contracts/kernel-membership.md § 4.
|
|
44
|
+
# This is the *kernel* (P1.3 lock), not "every always-rule". After P4 the
|
|
45
|
+
# `type:` frontmatter no longer maps 1:1 to kernel; the kernel is this set.
|
|
46
|
+
KERNEL_RULES: frozenset[str] = frozenset(
|
|
47
|
+
{
|
|
48
|
+
"agent-authority",
|
|
49
|
+
"ask-when-uncertain",
|
|
50
|
+
"commit-policy",
|
|
51
|
+
"direct-answers",
|
|
52
|
+
"language-and-tone",
|
|
53
|
+
"no-cheap-questions",
|
|
54
|
+
"non-destructive-by-default",
|
|
55
|
+
"scope-control",
|
|
56
|
+
"verify-before-complete",
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def strip_frontmatter(text: str) -> tuple[str, dict[str, str]]:
|
|
62
|
+
"""Strip leading YAML frontmatter and return (body, fields).
|
|
63
|
+
|
|
64
|
+
Minimal parser — handles `key: "value"` / `key: value` only. No nested
|
|
65
|
+
structures, no lists. Sufficient for the rule frontmatter contract.
|
|
66
|
+
"""
|
|
67
|
+
if not text.startswith("---\n"):
|
|
68
|
+
return text, {}
|
|
69
|
+
end = text.find("\n---\n", 4)
|
|
70
|
+
if end == -1:
|
|
71
|
+
return text, {}
|
|
72
|
+
raw = text[4:end]
|
|
73
|
+
body = text[end + 5 :]
|
|
74
|
+
fields: dict[str, str] = {}
|
|
75
|
+
for line in raw.splitlines():
|
|
76
|
+
if ":" not in line or line.startswith("#"):
|
|
77
|
+
continue
|
|
78
|
+
key, _, val = line.partition(":")
|
|
79
|
+
fields[key.strip()] = val.strip().strip('"').strip("'")
|
|
80
|
+
return body, fields
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def measure_rule(path: Path) -> dict[str, object]:
|
|
84
|
+
text = path.read_text(encoding="utf-8")
|
|
85
|
+
body, fields = strip_frontmatter(text)
|
|
86
|
+
return {
|
|
87
|
+
"id": path.stem,
|
|
88
|
+
"type": fields.get("type", "auto"),
|
|
89
|
+
"tier": fields.get("tier", ""),
|
|
90
|
+
"chars": len(body),
|
|
91
|
+
"lines": body.count("\n"),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def collect() -> list[dict[str, object]]:
|
|
96
|
+
rules = [measure_rule(p) for p in sorted(RULES_DIR.glob("*.md"))]
|
|
97
|
+
return rules
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def load_overrides() -> set[str]:
|
|
101
|
+
"""Read iron-law-override allowlist (one rule-id per line, '#' comments)."""
|
|
102
|
+
if not OVERRIDES_FILE.exists():
|
|
103
|
+
return set()
|
|
104
|
+
out: set[str] = set()
|
|
105
|
+
for line in OVERRIDES_FILE.read_text(encoding="utf-8").splitlines():
|
|
106
|
+
s = line.split("#", 1)[0].strip()
|
|
107
|
+
if s:
|
|
108
|
+
out.add(s)
|
|
109
|
+
return out
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def aggregate(rules: list[dict[str, object]]) -> dict[str, object]:
|
|
113
|
+
always = [r for r in rules if r["type"] == "always"]
|
|
114
|
+
auto = [r for r in rules if r["type"] == "auto"]
|
|
115
|
+
kernel = [r for r in rules if r["id"] in KERNEL_RULES]
|
|
116
|
+
total_chars = sum(int(r["chars"]) for r in rules)
|
|
117
|
+
return {
|
|
118
|
+
"always_count": len(always),
|
|
119
|
+
"auto_count": len(auto),
|
|
120
|
+
"kernel_count": len(kernel),
|
|
121
|
+
"rule_count": len(rules),
|
|
122
|
+
"always_chars": sum(int(r["chars"]) for r in always),
|
|
123
|
+
"auto_chars": sum(int(r["chars"]) for r in auto),
|
|
124
|
+
"kernel_chars": sum(int(r["chars"]) for r in kernel),
|
|
125
|
+
"total_chars": total_chars,
|
|
126
|
+
"kernel_hard": KERNEL_HARD,
|
|
127
|
+
"kernel_target": KERNEL_TARGET,
|
|
128
|
+
"per_rule_hard": PER_RULE_HARD,
|
|
129
|
+
"per_rule_target": PER_RULE_TARGET,
|
|
130
|
+
"per_rule_override_ceiling": PER_RULE_OVERRIDE_CEILING,
|
|
131
|
+
"oversize_rules": sorted(
|
|
132
|
+
(r for r in rules if int(r["chars"]) > PER_RULE_HARD),
|
|
133
|
+
key=lambda r: (-int(r["chars"]), r["id"]),
|
|
134
|
+
),
|
|
135
|
+
"top5_largest": sorted(rules, key=lambda r: (-int(r["chars"]), r["id"]))[:5],
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def render_table(rules: list[dict[str, object]], agg: dict[str, object]) -> str:
|
|
140
|
+
lines: list[str] = []
|
|
141
|
+
lines.append("Rule budget — source: .agent-src.uncompressed/rules/")
|
|
142
|
+
lines.append("")
|
|
143
|
+
lines.append(f"{'id':<40} {'type':<7} {'tier':<5} {'chars':>7}")
|
|
144
|
+
lines.append("-" * 62)
|
|
145
|
+
for r in sorted(rules, key=lambda r: r["id"]):
|
|
146
|
+
flag = "!" if int(r["chars"]) > PER_RULE_HARD else (
|
|
147
|
+
"~" if int(r["chars"]) > PER_RULE_TARGET else " "
|
|
148
|
+
)
|
|
149
|
+
lines.append(
|
|
150
|
+
f"{r['id']:<40} {r['type']:<7} {str(r['tier']):<5} {r['chars']:>6}{flag}"
|
|
151
|
+
)
|
|
152
|
+
lines.append("")
|
|
153
|
+
lines.append(
|
|
154
|
+
f"kernel-bucket: {agg['kernel_chars']:>6} chars across {agg['kernel_count']} rules "
|
|
155
|
+
f"(target ≤ {KERNEL_TARGET}, hard ≤ {KERNEL_HARD})"
|
|
156
|
+
)
|
|
157
|
+
lines.append(
|
|
158
|
+
f"always-bucket: {agg['always_chars']:>6} chars across {agg['always_count']} rules "
|
|
159
|
+
f"(legacy frontmatter `type: always`)"
|
|
160
|
+
)
|
|
161
|
+
lines.append(
|
|
162
|
+
f" auto-bucket: {agg['auto_chars']:>6} chars across {agg['auto_count']} rules"
|
|
163
|
+
)
|
|
164
|
+
lines.append(f" total: {agg['total_chars']:>6} chars across {agg['rule_count']} rules")
|
|
165
|
+
lines.append("")
|
|
166
|
+
lines.append(f"top-5 largest:")
|
|
167
|
+
for r in agg["top5_largest"]: # type: ignore[index]
|
|
168
|
+
lines.append(f" {r['chars']:>5} {r['id']} ({r['type']})")
|
|
169
|
+
over = agg["oversize_rules"] # type: ignore[index]
|
|
170
|
+
if over:
|
|
171
|
+
lines.append("")
|
|
172
|
+
lines.append(f"OVER per-rule hard cap ({PER_RULE_HARD} chars): {len(over)} rule(s)")
|
|
173
|
+
return "\n".join(lines)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def kernel_budget_check(
|
|
177
|
+
rules: list[dict[str, object]], agg: dict[str, object], overrides: set[str]
|
|
178
|
+
) -> tuple[int, list[str]]:
|
|
179
|
+
"""Enforce kernel budget per Council R2 amendments.
|
|
180
|
+
|
|
181
|
+
Returns (exit_code, report_lines). Exit 0 = pass, 1 = breach.
|
|
182
|
+
|
|
183
|
+
Checks:
|
|
184
|
+
- Kernel-bucket sum ≤ KERNEL_HARD (25k).
|
|
185
|
+
- Each kernel rule ≤ PER_RULE_HARD (2.5k), unless listed in
|
|
186
|
+
`iron-law-overrides.txt` (then ≤ PER_RULE_OVERRIDE_CEILING = 4k).
|
|
187
|
+
- Missing kernel rules (rule-id in KERNEL_RULES but no file) → fail.
|
|
188
|
+
"""
|
|
189
|
+
out: list[str] = []
|
|
190
|
+
fails: list[str] = []
|
|
191
|
+
|
|
192
|
+
kernel_rules = [r for r in rules if r["id"] in KERNEL_RULES]
|
|
193
|
+
found_ids = {str(r["id"]) for r in kernel_rules}
|
|
194
|
+
missing = sorted(KERNEL_RULES - found_ids)
|
|
195
|
+
for mid in missing:
|
|
196
|
+
fails.append(f"missing kernel rule: {mid} (declared in KERNEL_RULES, no file found)")
|
|
197
|
+
|
|
198
|
+
bucket = int(agg["kernel_chars"])
|
|
199
|
+
out.append(
|
|
200
|
+
f"kernel-bucket: {bucket} / {KERNEL_HARD} chars "
|
|
201
|
+
f"({agg['kernel_count']} rules)"
|
|
202
|
+
)
|
|
203
|
+
if bucket > KERNEL_HARD:
|
|
204
|
+
fails.append(f"kernel-bucket {bucket} > hard cap {KERNEL_HARD}")
|
|
205
|
+
|
|
206
|
+
out.append(
|
|
207
|
+
f"per-rule cap: {PER_RULE_HARD} (override ceiling {PER_RULE_OVERRIDE_CEILING} "
|
|
208
|
+
f"with ADR; allowlist {OVERRIDES_FILE.relative_to(REPO_ROOT)})"
|
|
209
|
+
)
|
|
210
|
+
out.append("")
|
|
211
|
+
out.append(f"{'id':<28} {'chars':>6} {'cap':>6} {'status':<24}")
|
|
212
|
+
out.append("-" * 68)
|
|
213
|
+
for r in sorted(kernel_rules, key=lambda r: r["id"]):
|
|
214
|
+
rid = str(r["id"])
|
|
215
|
+
chars = int(r["chars"])
|
|
216
|
+
if rid in overrides:
|
|
217
|
+
cap = PER_RULE_OVERRIDE_CEILING
|
|
218
|
+
label = "OK (override)"
|
|
219
|
+
if chars > cap:
|
|
220
|
+
label = f"FAIL (>{cap} ceiling)"
|
|
221
|
+
fails.append(f"{rid} {chars} > override ceiling {cap}")
|
|
222
|
+
else:
|
|
223
|
+
cap = PER_RULE_HARD
|
|
224
|
+
if chars > cap:
|
|
225
|
+
label = "FAIL (needs override ADR)"
|
|
226
|
+
fails.append(f"{rid} {chars} > per-rule hard cap {cap} (no override)")
|
|
227
|
+
elif chars > PER_RULE_TARGET:
|
|
228
|
+
label = "warn (> target)"
|
|
229
|
+
else:
|
|
230
|
+
label = "OK"
|
|
231
|
+
out.append(f"{rid:<28} {chars:>6} {cap:>6} {label:<24}")
|
|
232
|
+
|
|
233
|
+
out.append("")
|
|
234
|
+
if fails:
|
|
235
|
+
out.append(f"❌ kernel budget check: {len(fails)} breach(es)")
|
|
236
|
+
for f in fails:
|
|
237
|
+
out.append(f" - {f}")
|
|
238
|
+
return 1, out
|
|
239
|
+
out.append(f"✅ kernel budget check: pass")
|
|
240
|
+
return 0, out
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def trend_append(agg: dict[str, object]) -> tuple[int, str]:
|
|
244
|
+
"""Append a daily snapshot to agents/.rule-budget-history.jsonl.
|
|
245
|
+
|
|
246
|
+
Idempotent per UTC day: if today's date already has a row, the file
|
|
247
|
+
is not modified. Snapshot fields: date, kernel_chars, auto_chars,
|
|
248
|
+
rule_count, total_chars. Read by `roadmap:progress` for the Kernel
|
|
249
|
+
track per `road-to-kernel-and-router.md` P5.3.
|
|
250
|
+
"""
|
|
251
|
+
today = _dt.datetime.now(_dt.timezone.utc).date().isoformat()
|
|
252
|
+
snapshot = {
|
|
253
|
+
"date": today,
|
|
254
|
+
"kernel_chars": int(agg["kernel_chars"]),
|
|
255
|
+
"auto_chars": int(agg["auto_chars"]),
|
|
256
|
+
"rule_count": int(agg["rule_count"]),
|
|
257
|
+
"total_chars": int(agg["total_chars"]),
|
|
258
|
+
}
|
|
259
|
+
TREND_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
260
|
+
if TREND_FILE.exists():
|
|
261
|
+
for line in TREND_FILE.read_text(encoding="utf-8").splitlines():
|
|
262
|
+
line = line.strip()
|
|
263
|
+
if not line:
|
|
264
|
+
continue
|
|
265
|
+
try:
|
|
266
|
+
row = json.loads(line)
|
|
267
|
+
except json.JSONDecodeError:
|
|
268
|
+
continue
|
|
269
|
+
if row.get("date") == today:
|
|
270
|
+
return 0, f"trend: {today} already recorded — no-op"
|
|
271
|
+
with TREND_FILE.open("a", encoding="utf-8") as fh:
|
|
272
|
+
fh.write(json.dumps(snapshot, sort_keys=True) + "\n")
|
|
273
|
+
return 0, f"trend: appended {today} → {TREND_FILE.relative_to(REPO_ROOT)}"
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def main(argv: list[str] | None = None) -> int:
|
|
277
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
278
|
+
parser.add_argument("--json", action="store_true", help="emit JSON instead of a table")
|
|
279
|
+
parser.add_argument(
|
|
280
|
+
"--kernel-budget-check",
|
|
281
|
+
action="store_true",
|
|
282
|
+
help="enforce Council R2 kernel-bucket + per-rule caps; exit 1 on breach",
|
|
283
|
+
)
|
|
284
|
+
parser.add_argument(
|
|
285
|
+
"--trend-append",
|
|
286
|
+
action="store_true",
|
|
287
|
+
help="append today's snapshot to agents/.rule-budget-history.jsonl (idempotent per UTC day)",
|
|
288
|
+
)
|
|
289
|
+
args = parser.parse_args(argv)
|
|
290
|
+
|
|
291
|
+
rules = collect()
|
|
292
|
+
agg = aggregate(rules)
|
|
293
|
+
|
|
294
|
+
if args.kernel_budget_check:
|
|
295
|
+
overrides = load_overrides()
|
|
296
|
+
code, report = kernel_budget_check(rules, agg, overrides)
|
|
297
|
+
print("\n".join(report))
|
|
298
|
+
return code
|
|
299
|
+
|
|
300
|
+
if args.trend_append:
|
|
301
|
+
code, msg = trend_append(agg)
|
|
302
|
+
print(msg)
|
|
303
|
+
return code
|
|
304
|
+
|
|
305
|
+
if args.json:
|
|
306
|
+
payload = {"rules": sorted(rules, key=lambda r: r["id"]), "summary": agg}
|
|
307
|
+
print(json.dumps(payload, indent=2, sort_keys=True))
|
|
308
|
+
else:
|
|
309
|
+
print(render_table(rules, agg))
|
|
310
|
+
return 0
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
if __name__ == "__main__":
|
|
314
|
+
sys.exit(main())
|
|
@@ -29,7 +29,7 @@ INELIGIBLE: dict[str, str] = {
|
|
|
29
29
|
"copilot-agents-init": "Project init — only deliberately during onboarding.",
|
|
30
30
|
"copilot-agents-optimize": "Maintenance refactor; only when the maintainer chooses to run it.",
|
|
31
31
|
"do-and-judge": "Subagent orchestration — overlaps /work and judge skills; keep explicit.",
|
|
32
|
-
"do-in-steps": "Subagent orchestration — overlaps /work and /roadmap
|
|
32
|
+
"do-in-steps": "Subagent orchestration — overlaps /work and /roadmap:process-*; keep explicit.",
|
|
33
33
|
"fix-portability": "Package-internal — only the event4u/agent-config repo runs this.",
|
|
34
34
|
"fix-references": "Package-internal — only the event4u/agent-config repo runs this.",
|
|
35
35
|
"judge": "Sibling of /review-changes — eligibility routed there; keep this explicit.",
|
|
@@ -89,7 +89,7 @@ ELIGIBLE: dict[str, tuple[str, str]] = {
|
|
|
89
89
|
"review-changes": ("self-review my changes, judge this diff before PR", "uncommitted or staged changes pre-PR"),
|
|
90
90
|
"review-routing": ("who should review this, suggest reviewers for this PR", "PR open without assigned reviewers"),
|
|
91
91
|
"roadmap-create": ("create a roadmap for X, plan this work as a roadmap", "multi-phase work without an existing agents/roadmaps/*.md"),
|
|
92
|
-
"roadmap-execute": ("
|
|
92
|
+
"roadmap-execute": ("process the roadmap, work through the roadmap autonomously, finish this phase", "existing agents/roadmaps/*.md referenced in the prompt"),
|
|
93
93
|
"rule-compliance-audit": ("audit my rules, check rule trigger quality", "maintainer working on .augment/rules/ files"),
|
|
94
94
|
"tests-create": ("write tests for these changes, add tests for this branch", "code changes on the branch without matching test changes"),
|
|
95
95
|
"tests-execute": ("run the tests, execute the test suite", "code changes pending verification"),
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Prototype contradiction linter (P1.1 of road-to-package-optimization).
|
|
4
|
+
|
|
5
|
+
Hard acceptance: must flag >=3 real cross-artifact contradictions in this
|
|
6
|
+
repo within 5 s wall-clock and < $0.01 cost (deterministic, no LLM calls).
|
|
7
|
+
On failure, the roadmap closes with the null result documented; no
|
|
8
|
+
Phase 2 work begins.
|
|
9
|
+
|
|
10
|
+
Heuristic family — three deterministic checks across rules, skills,
|
|
11
|
+
commands, and contexts:
|
|
12
|
+
|
|
13
|
+
1. Routing mismatch: rule frontmatter `routes_to: [skill:foo]` but the
|
|
14
|
+
target artifact does not exist or has no matching trigger.
|
|
15
|
+
2. Trigger collision with imperative conflict: two artifacts share a
|
|
16
|
+
trigger keyword AND one body contains an `ALWAYS X` Iron Law while
|
|
17
|
+
the other contains `NEVER X` (or `MUST` vs `MUST NOT`) on the same
|
|
18
|
+
verb-object.
|
|
19
|
+
3. Catalog drift: a token-optimizer-style catalog row cites a path that
|
|
20
|
+
does not exist (subset of #1, broader scope than the freshness gate).
|
|
21
|
+
|
|
22
|
+
Stdlib only. JSON to stdout. Exit 0 = clean / Exit 1 = contradictions found.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import re
|
|
29
|
+
import sys
|
|
30
|
+
import time
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
REPO = Path(__file__).resolve().parent.parent
|
|
34
|
+
SRC = REPO / ".agent-src.uncompressed"
|
|
35
|
+
|
|
36
|
+
ARTIFACT_DIRS = {
|
|
37
|
+
"rule": SRC / "rules",
|
|
38
|
+
"skill": SRC / "skills",
|
|
39
|
+
"command": SRC / "commands",
|
|
40
|
+
"context": SRC / "contexts",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
FM_RE = re.compile(r"^---\n(.*?)\n---\n", re.DOTALL)
|
|
44
|
+
ALWAYS_RE = re.compile(r"^\s*(ALWAYS|MUST)\s+([A-Z][^.\n]{2,80})", re.MULTILINE)
|
|
45
|
+
NEVER_RE = re.compile(r"^\s*(NEVER|MUST NOT|DO NOT)\s+([A-Z][^.\n]{2,80})", re.MULTILINE)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def parse_artifact(path: Path, kind: str) -> dict:
|
|
49
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
50
|
+
fm: dict = {}
|
|
51
|
+
m = FM_RE.match(text)
|
|
52
|
+
body = text
|
|
53
|
+
if m:
|
|
54
|
+
body = text[m.end():]
|
|
55
|
+
for line in m.group(1).splitlines():
|
|
56
|
+
if ":" in line and not line.startswith(" "):
|
|
57
|
+
k, _, v = line.partition(":")
|
|
58
|
+
fm[k.strip()] = v.strip()
|
|
59
|
+
triggers = re.findall(r"`([a-z][a-z0-9_-]+)`", fm.get("description", ""))
|
|
60
|
+
routes = re.findall(r"(skill|rule|command):([a-z0-9_-]+)", fm.get("routes_to", ""))
|
|
61
|
+
always = [m.group(2).strip() for m in ALWAYS_RE.finditer(body)]
|
|
62
|
+
never = [m.group(2).strip() for m in NEVER_RE.finditer(body)]
|
|
63
|
+
return {
|
|
64
|
+
"kind": kind,
|
|
65
|
+
"path": str(path.relative_to(REPO)),
|
|
66
|
+
"id": path.stem if path.name != "SKILL.md" else path.parent.name,
|
|
67
|
+
"triggers": set(triggers),
|
|
68
|
+
"routes": routes,
|
|
69
|
+
"always": always,
|
|
70
|
+
"never": never,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def collect() -> list[dict]:
|
|
75
|
+
out: list[dict] = []
|
|
76
|
+
for kind, root in ARTIFACT_DIRS.items():
|
|
77
|
+
if not root.exists():
|
|
78
|
+
continue
|
|
79
|
+
for p in root.rglob("*.md"):
|
|
80
|
+
if p.name in {"README.md", "INDEX.md"}:
|
|
81
|
+
continue
|
|
82
|
+
out.append(parse_artifact(p, kind))
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def check_routing(arts: list[dict]) -> list[dict]:
|
|
87
|
+
by_id = {(a["kind"], a["id"]): a for a in arts}
|
|
88
|
+
flags: list[dict] = []
|
|
89
|
+
for a in arts:
|
|
90
|
+
for tgt_kind, tgt_id in a["routes"]:
|
|
91
|
+
if (tgt_kind, tgt_id) not in by_id:
|
|
92
|
+
flags.append({
|
|
93
|
+
"type": "routing_mismatch",
|
|
94
|
+
"artifact_a": a["path"],
|
|
95
|
+
"artifact_b": f"{tgt_kind}:{tgt_id} (missing)",
|
|
96
|
+
"evidence": f"{a['id']} routes_to {tgt_kind}:{tgt_id}, target not found",
|
|
97
|
+
})
|
|
98
|
+
return flags
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def normalize_verb(s: str) -> str:
|
|
102
|
+
return re.sub(r"[^a-z ]+", "", s.lower()).split(" ", 1)[0] if s else ""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def check_imperative_conflict(arts: list[dict]) -> list[dict]:
|
|
106
|
+
flags: list[dict] = []
|
|
107
|
+
by_trigger: dict[str, list[dict]] = {}
|
|
108
|
+
for a in arts:
|
|
109
|
+
for t in a["triggers"]:
|
|
110
|
+
by_trigger.setdefault(t, []).append(a)
|
|
111
|
+
for trigger, group in by_trigger.items():
|
|
112
|
+
if len(group) < 2:
|
|
113
|
+
continue
|
|
114
|
+
for i, a in enumerate(group):
|
|
115
|
+
for b in group[i + 1:]:
|
|
116
|
+
a_verbs = {normalize_verb(s) for s in a["always"]}
|
|
117
|
+
b_verbs = {normalize_verb(s) for s in b["never"]}
|
|
118
|
+
conflict = a_verbs & b_verbs - {""}
|
|
119
|
+
if conflict:
|
|
120
|
+
flags.append({
|
|
121
|
+
"type": "imperative_conflict",
|
|
122
|
+
"artifact_a": a["path"],
|
|
123
|
+
"artifact_b": b["path"],
|
|
124
|
+
"evidence": f"shared trigger '{trigger}', a says ALWAYS {sorted(conflict)}, b says NEVER {sorted(conflict)}",
|
|
125
|
+
})
|
|
126
|
+
return flags
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main() -> int:
|
|
130
|
+
t0 = time.monotonic()
|
|
131
|
+
arts = collect()
|
|
132
|
+
flags = check_routing(arts) + check_imperative_conflict(arts)
|
|
133
|
+
elapsed = time.monotonic() - t0
|
|
134
|
+
report = {
|
|
135
|
+
"artifacts_scanned": len(arts),
|
|
136
|
+
"elapsed_seconds": round(elapsed, 3),
|
|
137
|
+
"flags": flags,
|
|
138
|
+
"acceptance": {
|
|
139
|
+
"min_flags": 3,
|
|
140
|
+
"max_seconds": 5.0,
|
|
141
|
+
"passed": len(flags) >= 3 and elapsed < 5.0,
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
json.dump(report, sys.stdout, indent=2)
|
|
145
|
+
sys.stdout.write("\n")
|
|
146
|
+
return 0 if not flags else 1
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
sys.exit(main())
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
50
50
|
"description": "Semver release in which this command became a shim (e.g. '1.15.0')."
|
|
51
51
|
},
|
|
52
|
+
"council_depth": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"enum": ["deep"],
|
|
55
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered by this command. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for architecture, refactoring, or bug-diagnosis commands. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
56
|
+
},
|
|
52
57
|
"suggestion": {
|
|
53
58
|
"type": "object",
|
|
54
59
|
"additionalProperties": false,
|
|
@@ -26,18 +26,72 @@
|
|
|
26
26
|
},
|
|
27
27
|
"load_context": {
|
|
28
28
|
"type": "array",
|
|
29
|
-
"items": {
|
|
30
|
-
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^((\\.\\./)*contexts/|agents/contexts/|\\.agent-src/contexts/)[^\\s]+\\.md$",
|
|
32
|
+
"description": "Logical name (preferred — `contexts/<area>/<file>.md`) or project-local (`agents/contexts/<file>.md`). The `.agent-src.uncompressed/` prefix is rejected by the regex; the rewriter (`scripts/compress.py::_rewrite_paths`) resolves logical names at compress time. Rewritten relative forms (`../contexts/...`, `../../contexts/...`) are accepted so the linter passes on the compressed mirror in CI."
|
|
33
|
+
},
|
|
34
|
+
"description": "Lazy on-demand context references. Use logical names rooted at the source (e.g. `contexts/execution/foo.md`); the `.agent-src.uncompressed/` prefix is forbidden by the regex (road-to-path-fixes.md P5.3). Path rules and budget caps enforced by scripts/lint_load_context.py. Contract: docs/contracts/load-context-schema.md."
|
|
31
35
|
},
|
|
32
36
|
"load_context_eager": {
|
|
33
37
|
"type": "array",
|
|
34
|
-
"items": {
|
|
35
|
-
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"pattern": "^((\\.\\./)*contexts/|agents/contexts/|\\.agent-src/contexts/)[^\\s]+\\.md$",
|
|
41
|
+
"description": "Same logical-name rule as `load_context`."
|
|
42
|
+
},
|
|
43
|
+
"description": "Eager auto-loaded context references. Same logical-name rule as `load_context`. Counts against the per-rule char budget; enforced by scripts/lint_load_context.py."
|
|
36
44
|
},
|
|
37
45
|
"tier": {
|
|
38
46
|
"type": "string",
|
|
39
|
-
"enum": ["1", "2a", "2b", "3", "safety-floor", "mechanical-already"],
|
|
40
|
-
"description": "Hardening tier
|
|
47
|
+
"enum": ["1", "2a", "2b", "3", "safety-floor", "mechanical-already", "kernel", "tier-1", "tier-2"],
|
|
48
|
+
"description": "Hardening tier. Legacy values (1/2a/2b/3/safety-floor/mechanical-already) accepted; new router-canonical values (kernel/tier-1/tier-2) introduced by road-to-kernel-and-router.md Phase 4."
|
|
49
|
+
},
|
|
50
|
+
"council_depth": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"enum": ["deep"],
|
|
53
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered while this rule is active. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for rules that gate architecture, refactoring, or bug-diagnosis flows. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
54
|
+
},
|
|
55
|
+
"triggers": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"properties": {
|
|
61
|
+
"keyword": {"type": "string"},
|
|
62
|
+
"phrase": {"type": "string"},
|
|
63
|
+
"intent": {"type": "string"},
|
|
64
|
+
"file_pattern": {"type": "string"},
|
|
65
|
+
"path_prefix": {"type": "string", "description": "Literal path-prefix match pattern the host evaluates against the file the agent is editing — NOT a file reference. The rewriter leaves it verbatim. Source-of-truth rules that must fire on edits under `.agent-src.uncompressed/` keep that prefix here (the prefix ban applies only to `load_context:` and body links — see road-to-path-fixes.md P2.2 / AI-Council 2026-05-06)."},
|
|
66
|
+
"command": {"type": "string"},
|
|
67
|
+
"reason": {"type": "string"}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"description": "Router activation triggers (Phase 3 of road-to-kernel-and-router.md). Forbidden on kernel rules, required on non-kernel rules. Schema: docs/contracts/rule-router.md."
|
|
71
|
+
},
|
|
72
|
+
"routes_to": {
|
|
73
|
+
"type": "array",
|
|
74
|
+
"items": {"type": "string", "pattern": "^(skill|guideline|command|contract):"},
|
|
75
|
+
"description": "Router targets (skill / guideline / command / contract). Forbidden on kernel rules. Schema: docs/contracts/rule-router.md."
|
|
76
|
+
},
|
|
77
|
+
"profile": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"enum": ["minimal", "balanced", "full"],
|
|
80
|
+
"description": "Optional profile override; rare. Tier-derived default applies otherwise."
|
|
81
|
+
},
|
|
82
|
+
"validator_ignore": {
|
|
83
|
+
"type": "array",
|
|
84
|
+
"items": {
|
|
85
|
+
"type": "object",
|
|
86
|
+
"additionalProperties": false,
|
|
87
|
+
"required": ["type", "pattern"],
|
|
88
|
+
"properties": {
|
|
89
|
+
"type": {"type": "string", "enum": ["substring", "regex"]},
|
|
90
|
+
"pattern": {"type": "string", "minLength": 1},
|
|
91
|
+
"reason": {"type": "string", "description": "Human-readable rationale for the suppression — surfaced in audit logs."}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"description": "Per-rule allowlist consumed by the post-compression validator (scripts/check_compressed_paths.py). Rules that document forbidden path substrings as their subject matter (e.g. augment-portability, no-roadmap-references) declare the literal strings here so the gate does not flag itself. road-to-path-fixes.md P5.1."
|
|
41
95
|
}
|
|
42
96
|
}
|
|
43
97
|
}
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"enum": ["senior"],
|
|
43
43
|
"description": "Optional tier marker. `senior` opts the skill into the Senior-Tier Required Structure check (Context-First lead, Related Skills, Proactive Triggers, Output Artifacts) per .agent-src.uncompressed/rules/skill-quality.md."
|
|
44
44
|
},
|
|
45
|
+
"council_depth": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"enum": ["deep"],
|
|
48
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered by this skill. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for architecture, refactoring, or bug-diagnosis skills. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
49
|
+
},
|
|
45
50
|
"execution": {
|
|
46
51
|
"type": "object",
|
|
47
52
|
"additionalProperties": false,
|