@event4u/agent-config 1.20.0 → 1.21.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 +1 -1
- package/.agent-src/commands/bug-investigate.md +2 -2
- 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 +17 -5
- package/.agent-src/commands/council.md +1 -1
- 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/jira-ticket.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.md +1 -1
- 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 +4 -4
- 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 +1 -1
- 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/model-recommendations.md +2 -2
- package/.agent-src/contexts/override-system.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 +10 -2
- 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/agent-docs-writing/SKILL.md +1 -1
- package/.agent-src/skills/ai-council/SKILL.md +65 -0
- 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 +5 -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/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/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 +2 -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 +21 -16
- 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/rule.md +127 -0
- package/.claude-plugin/marketplace.json +4 -1
- package/AGENTS.md +32 -5
- package/CHANGELOG.md +69 -3
- package/README.md +22 -21
- package/config/agent-settings.template.yml +44 -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/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-rule-kernel-and-router.md +122 -0
- package/docs/getting-started.md +2 -2
- 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/_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 +9 -5
- 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/prototype_lint_contradictions.py +150 -0
- package/scripts/schemas/rule.schema.json +55 -6
- package/scripts/skill_linter.py +196 -6
- package/scripts/smoke_path_resolution.py +93 -0
- package/scripts/validate_frontmatter.py +41 -1
- 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
package/scripts/skill_linter.py
CHANGED
|
@@ -117,6 +117,17 @@ VALID_RULE_TYPES = {"always", "auto"}
|
|
|
117
117
|
VALID_RULE_SOURCES = {"package", "project"}
|
|
118
118
|
VALID_STATUSES = {"active", "deprecated", "superseded"}
|
|
119
119
|
|
|
120
|
+
# --- Router schema (docs/contracts/rule-router.md) ---
|
|
121
|
+
ROUTER_ALLOWED_TRIGGER_KEYS = {"keyword", "phrase", "intent", "file_pattern",
|
|
122
|
+
"path_prefix", "command"}
|
|
123
|
+
ROUTER_ALLOWED_PROFILES = {"minimal", "balanced", "full"}
|
|
124
|
+
KERNEL_RULE_IDS: set[str] = {
|
|
125
|
+
"agent-authority", "ask-when-uncertain", "commit-policy",
|
|
126
|
+
"direct-answers", "language-and-tone", "no-cheap-questions",
|
|
127
|
+
"non-destructive-by-default", "scope-control",
|
|
128
|
+
"verify-before-complete",
|
|
129
|
+
}
|
|
130
|
+
|
|
120
131
|
# --- Runtime execution metadata constants ---
|
|
121
132
|
VALID_EXECUTION_TYPES = {"manual", "assisted", "automated"}
|
|
122
133
|
VALID_EXECUTION_HANDLERS = {"none", "shell", "php", "node", "internal"}
|
|
@@ -220,6 +231,42 @@ def extract_sections(text: str) -> set[str]:
|
|
|
220
231
|
return {match.group(1).strip() for match in SECTION_PATTERN.finditer(text)}
|
|
221
232
|
|
|
222
233
|
|
|
234
|
+
def _count_code_blocks(text: str) -> int:
|
|
235
|
+
"""Return the number of fenced code blocks (``` … ```) in *text*."""
|
|
236
|
+
fence_count = 0
|
|
237
|
+
for line in text.splitlines():
|
|
238
|
+
stripped = line.lstrip()
|
|
239
|
+
if stripped.startswith("```"):
|
|
240
|
+
fence_count += 1
|
|
241
|
+
return fence_count // 2
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _fenced_content_ratio(text: str) -> float:
|
|
245
|
+
"""Return the fraction of non-empty lines that sit inside fenced blocks.
|
|
246
|
+
|
|
247
|
+
Used as a structural signal: rules / files dominated by verbatim Iron-Law
|
|
248
|
+
blocks or worked examples score high and are exempted from raw line-count
|
|
249
|
+
warnings (council review 2026-05-06).
|
|
250
|
+
"""
|
|
251
|
+
inside = False
|
|
252
|
+
fenced_lines = 0
|
|
253
|
+
non_empty = 0
|
|
254
|
+
for line in text.splitlines():
|
|
255
|
+
stripped = line.strip()
|
|
256
|
+
if stripped.startswith("```"):
|
|
257
|
+
inside = not inside
|
|
258
|
+
if stripped:
|
|
259
|
+
non_empty += 1
|
|
260
|
+
continue
|
|
261
|
+
if stripped:
|
|
262
|
+
non_empty += 1
|
|
263
|
+
if inside:
|
|
264
|
+
fenced_lines += 1
|
|
265
|
+
if non_empty == 0:
|
|
266
|
+
return 0.0
|
|
267
|
+
return fenced_lines / non_empty
|
|
268
|
+
|
|
269
|
+
|
|
223
270
|
def extract_description(text: str) -> Optional[str]:
|
|
224
271
|
frontmatter = FRONTMATTER_PATTERN.search(text)
|
|
225
272
|
if not frontmatter:
|
|
@@ -495,8 +542,12 @@ def lint_skill(path: Path, text: str) -> LintResult:
|
|
|
495
542
|
suggestions.append("Add a requirement-checking or validation step before implementation")
|
|
496
543
|
|
|
497
544
|
# --- Size check (see guidelines/agent-infra/size-and-scope.md) ---
|
|
545
|
+
# Threshold raised from 300 → 400 (council review 2026-05-06): reference-rich
|
|
546
|
+
# skills (quality-tools 411, ai-council 399, project-analyzer 341) legitimately
|
|
547
|
+
# exceed 300 lines without being split-candidates. Structural follow-up tracked
|
|
548
|
+
# in agents/roadmaps/road-to-structural-linter-reform.md.
|
|
498
549
|
total_lines = len(text.splitlines())
|
|
499
|
-
if total_lines >
|
|
550
|
+
if total_lines > 400:
|
|
500
551
|
issues.append(Issue("warning", "skill_too_large", f"Skill has {total_lines} lines; review for split (see size-and-scope guideline)"))
|
|
501
552
|
|
|
502
553
|
# --- Pointer-only / guideline-dependent skill detection ---
|
|
@@ -553,6 +604,131 @@ def extract_frontmatter(text: str) -> Optional[str]:
|
|
|
553
604
|
return match.group(1) if match else None
|
|
554
605
|
|
|
555
606
|
|
|
607
|
+
def _parse_yaml_list(frontmatter: str, key: str) -> Optional[list]:
|
|
608
|
+
"""Parse a simple top-level YAML list `key:` from frontmatter.
|
|
609
|
+
|
|
610
|
+
Supports the two shapes we emit in rule frontmatter:
|
|
611
|
+
triggers:
|
|
612
|
+
- keyword: "foo"
|
|
613
|
+
- phrase: "bar baz"
|
|
614
|
+
routes_to:
|
|
615
|
+
- skill:php-coder
|
|
616
|
+
- guideline:agent-infra/asking-and-brevity-examples
|
|
617
|
+
|
|
618
|
+
Returns ``None`` if the key is absent (so the caller can distinguish
|
|
619
|
+
"missing" from "empty"); returns ``[]`` for an explicitly empty list.
|
|
620
|
+
"""
|
|
621
|
+
lines = frontmatter.splitlines()
|
|
622
|
+
out: list = []
|
|
623
|
+
in_block = False
|
|
624
|
+
for line in lines:
|
|
625
|
+
if not in_block:
|
|
626
|
+
if line.startswith(f"{key}:"):
|
|
627
|
+
rhs = line[len(key) + 1:].strip()
|
|
628
|
+
if rhs in ("", "[]"):
|
|
629
|
+
if rhs == "[]":
|
|
630
|
+
return []
|
|
631
|
+
in_block = True
|
|
632
|
+
else:
|
|
633
|
+
return None # unexpected scalar shape
|
|
634
|
+
continue
|
|
635
|
+
if line.startswith(" - "):
|
|
636
|
+
item = line[4:].strip()
|
|
637
|
+
if ":" in item and not item.startswith(("'", '"')):
|
|
638
|
+
k, _, v = item.partition(":")
|
|
639
|
+
out.append({k.strip(): v.strip().strip('"').strip("'")})
|
|
640
|
+
else:
|
|
641
|
+
out.append(item.strip('"').strip("'"))
|
|
642
|
+
elif line.strip() == "" or line.startswith(" "):
|
|
643
|
+
continue
|
|
644
|
+
else:
|
|
645
|
+
break
|
|
646
|
+
return out if in_block else None
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def lint_router_frontmatter(rule_id: str, frontmatter: str,
|
|
650
|
+
rule_type: Optional[str]) -> List[Issue]:
|
|
651
|
+
"""Validate `triggers:` / `routes_to:` per docs/contracts/rule-router.md.
|
|
652
|
+
|
|
653
|
+
Strict checks (always errors): kernel rules MUST NOT carry router fields;
|
|
654
|
+
`triggers:` items must use one allowed key; `routes_to:` items must
|
|
655
|
+
follow `kind:id` with kind ∈ {skill, guideline} and the target file
|
|
656
|
+
must exist on disk.
|
|
657
|
+
|
|
658
|
+
Lenient checks (info-level until Phase 4 migrations land): non-kernel
|
|
659
|
+
rules without `triggers:` / `routes_to:` get an informational note,
|
|
660
|
+
not an error — the existing description-matching path still works.
|
|
661
|
+
"""
|
|
662
|
+
issues: List[Issue] = []
|
|
663
|
+
triggers = _parse_yaml_list(frontmatter, "triggers")
|
|
664
|
+
routes_to = _parse_yaml_list(frontmatter, "routes_to")
|
|
665
|
+
|
|
666
|
+
is_kernel = rule_id in KERNEL_RULE_IDS or rule_type == "always"
|
|
667
|
+
|
|
668
|
+
if is_kernel:
|
|
669
|
+
if triggers is not None:
|
|
670
|
+
issues.append(Issue("error", "kernel_has_triggers",
|
|
671
|
+
"Kernel rules MUST NOT declare triggers: (kernel is unconditional)"))
|
|
672
|
+
if routes_to is not None:
|
|
673
|
+
issues.append(Issue("error", "kernel_has_routes_to",
|
|
674
|
+
"Kernel rules MUST NOT declare routes_to: (kernel body stays inline)"))
|
|
675
|
+
return issues
|
|
676
|
+
|
|
677
|
+
# Non-kernel rule path
|
|
678
|
+
if triggers is None:
|
|
679
|
+
issues.append(Issue("info", "router_triggers_missing",
|
|
680
|
+
"Non-kernel rule has no triggers: — falls back to description matching "
|
|
681
|
+
"until Phase 4 migration lands"))
|
|
682
|
+
else:
|
|
683
|
+
for idx, item in enumerate(triggers):
|
|
684
|
+
if not isinstance(item, dict) or len(item) != 1:
|
|
685
|
+
issues.append(Issue("error", "trigger_shape_invalid",
|
|
686
|
+
f"triggers[{idx}] must be a single-key mapping"))
|
|
687
|
+
continue
|
|
688
|
+
(k,) = item.keys()
|
|
689
|
+
if k not in ROUTER_ALLOWED_TRIGGER_KEYS:
|
|
690
|
+
allowed = ", ".join(sorted(ROUTER_ALLOWED_TRIGGER_KEYS))
|
|
691
|
+
issues.append(Issue("error", "trigger_key_unknown",
|
|
692
|
+
f"triggers[{idx}] key '{k}' not in allowed set ({allowed})"))
|
|
693
|
+
|
|
694
|
+
if routes_to is None:
|
|
695
|
+
issues.append(Issue("info", "router_routes_to_missing",
|
|
696
|
+
"Non-kernel rule has no routes_to: — body should migrate to skill / "
|
|
697
|
+
"guideline in Phase 4"))
|
|
698
|
+
else:
|
|
699
|
+
repo_root = Path(__file__).resolve().parent.parent
|
|
700
|
+
for idx, item in enumerate(routes_to):
|
|
701
|
+
if not isinstance(item, str) or ":" not in item:
|
|
702
|
+
issues.append(Issue("error", "route_shape_invalid",
|
|
703
|
+
f"routes_to[{idx}] must be 'kind:id'"))
|
|
704
|
+
continue
|
|
705
|
+
kind, _, target_id = item.partition(":")
|
|
706
|
+
if kind == "skill":
|
|
707
|
+
target = repo_root / ".agent-src.uncompressed" / "skills" / target_id / "SKILL.md"
|
|
708
|
+
elif kind == "guideline":
|
|
709
|
+
target = repo_root / "docs" / "guidelines" / f"{target_id}.md"
|
|
710
|
+
elif kind == "command":
|
|
711
|
+
target = repo_root / ".agent-src.uncompressed" / "commands" / f"{target_id}.md"
|
|
712
|
+
elif kind == "contract":
|
|
713
|
+
# Contracts live in two places: stable host docs in
|
|
714
|
+
# docs/contracts/ and load-bearing flows in
|
|
715
|
+
# .agent-src.uncompressed/contexts/contracts/ (road-to-path-fixes
|
|
716
|
+
# P4 / Council R2). Try both before failing.
|
|
717
|
+
target = repo_root / "docs" / "contracts" / f"{target_id}.md"
|
|
718
|
+
if not target.exists():
|
|
719
|
+
alt = repo_root / ".agent-src.uncompressed" / "contexts" / "contracts" / f"{target_id}.md"
|
|
720
|
+
if alt.exists():
|
|
721
|
+
target = alt
|
|
722
|
+
else:
|
|
723
|
+
issues.append(Issue("error", "route_kind_unknown",
|
|
724
|
+
f"routes_to[{idx}] kind '{kind}' must be 'skill', 'guideline', 'command', or 'contract'"))
|
|
725
|
+
continue
|
|
726
|
+
if not target.exists():
|
|
727
|
+
issues.append(Issue("error", "route_target_missing",
|
|
728
|
+
f"routes_to[{idx}] target '{item}' not found at {target}"))
|
|
729
|
+
return issues
|
|
730
|
+
|
|
731
|
+
|
|
556
732
|
def extract_frontmatter_field(frontmatter: str, pattern: re.Pattern[str]) -> Optional[str]:
|
|
557
733
|
match = pattern.search(frontmatter)
|
|
558
734
|
return match.group(1).strip() if match else None
|
|
@@ -801,6 +977,9 @@ def lint_rule(path: Path, text: str) -> LintResult:
|
|
|
801
977
|
f"Always-rule with topic-specific description ({', '.join(topic_keywords)}) — "
|
|
802
978
|
f"consider auto type per rule-type-governance"))
|
|
803
979
|
|
|
980
|
+
# Router schema validation (docs/contracts/rule-router.md, Phase 3.3).
|
|
981
|
+
issues.extend(lint_router_frontmatter(path.stem, frontmatter, rule_type))
|
|
982
|
+
|
|
804
983
|
# --- Structure checks ---
|
|
805
984
|
# H1 heading
|
|
806
985
|
if not H1_PATTERN.search(text):
|
|
@@ -817,14 +996,18 @@ def lint_rule(path: Path, text: str) -> LintResult:
|
|
|
817
996
|
issues.append(Issue("warning", "double_blank_lines", "File contains double or triple blank lines"))
|
|
818
997
|
|
|
819
998
|
# --- Content checks (see guidelines/agent-infra/size-and-scope.md) ---
|
|
999
|
+
# Length thresholds gated by fenced-content density (council review 2026-05-06):
|
|
1000
|
+
# rules dominated by verbatim Iron-Law blocks / worked examples are protected
|
|
1001
|
+
# from the > 40 / > 60 warnings. Hard error at 200 stays unconditional.
|
|
820
1002
|
line_count = len([line for line in text.splitlines() if line.strip()])
|
|
821
1003
|
total_lines = len(text.splitlines())
|
|
1004
|
+
fenced_ratio = _fenced_content_ratio(text)
|
|
822
1005
|
if total_lines > 200:
|
|
823
1006
|
issues.append(Issue("error", "rule_too_large", f"Rule has {total_lines} lines (hard limit: 200); must split or move to guideline"))
|
|
824
|
-
elif line_count > 60:
|
|
825
|
-
issues.append(Issue("warning", "long_rule", f"Rule has {line_count} non-empty lines; prefer < 60 (see size-and-scope guideline)"))
|
|
826
|
-
elif line_count > 40:
|
|
827
|
-
issues.append(Issue("warning", "long_rule", f"Rule has {line_count} non-empty lines; rules should be concise"))
|
|
1007
|
+
elif line_count > 60 and fenced_ratio < 0.30:
|
|
1008
|
+
issues.append(Issue("warning", "long_rule", f"Rule has {line_count} non-empty lines (fenced-content {fenced_ratio:.0%}); prefer < 60 (see size-and-scope guideline)"))
|
|
1009
|
+
elif line_count > 40 and fenced_ratio < 0.30:
|
|
1010
|
+
issues.append(Issue("warning", "long_rule", f"Rule has {line_count} non-empty lines (fenced-content {fenced_ratio:.0%}); rules should be concise"))
|
|
828
1011
|
|
|
829
1012
|
for bad_sign in RULE_BAD_SIGNS:
|
|
830
1013
|
if bad_sign in text:
|
|
@@ -969,9 +1152,16 @@ def lint_command(path: Path, text: str) -> LintResult:
|
|
|
969
1152
|
issues.append(Issue("warning", "no_steps", "Command has no Steps section or numbered sub-headings"))
|
|
970
1153
|
|
|
971
1154
|
# --- Size check (see guidelines/agent-infra/size-and-scope.md) ---
|
|
1155
|
+
# Word threshold (1000) gated by structural delegation signal (council review
|
|
1156
|
+
# 2026-05-06): well-factored orchestrators with ≥ 5 sub-sections AND ≥ 3 code
|
|
1157
|
+
# blocks are exempt — the size reflects dispatch breadth, not bloat.
|
|
972
1158
|
word_count = len(text.split())
|
|
973
1159
|
if word_count > 1000:
|
|
974
|
-
|
|
1160
|
+
section_count = len(sections)
|
|
1161
|
+
code_block_count = _count_code_blocks(text)
|
|
1162
|
+
delegation_signal = section_count >= 5 and code_block_count >= 3
|
|
1163
|
+
if not delegation_signal:
|
|
1164
|
+
issues.append(Issue("warning", "large_command", f"Command has {word_count} words (target: 200-600, max ~1000); {section_count} sub-sections, {code_block_count} code blocks — lacks delegation structure"))
|
|
975
1165
|
|
|
976
1166
|
# File must end with exactly one newline
|
|
977
1167
|
if not text.endswith("\n"):
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Smoke-test path resolution against the package's own `.augment/` projection.
|
|
3
|
+
|
|
4
|
+
Per `agents/roadmaps/road-to-path-fixes.md` Phase 7 (Council Decision 3,
|
|
5
|
+
2026-05-06): the package's `.augment/` tree has the same shape as the
|
|
6
|
+
`.augment/` tree a consumer would receive after `scripts/install.sh`.
|
|
7
|
+
If `load_context:` entries resolve cleanly here, they resolve cleanly
|
|
8
|
+
in any consumer.
|
|
9
|
+
|
|
10
|
+
What it does:
|
|
11
|
+
- Walks `.augment/rules/*.md`.
|
|
12
|
+
- Parses each rule's YAML frontmatter.
|
|
13
|
+
- Resolves every `load_context:` and `load_context_eager:` entry
|
|
14
|
+
against the rule file's directory.
|
|
15
|
+
- Reports any miss with a file:entry line.
|
|
16
|
+
|
|
17
|
+
Exit codes: 0 = all entries resolve, 1 = one or more misses, 3 = no
|
|
18
|
+
`.augment/rules/` directory found (run `task sync` first).
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
import yaml
|
|
26
|
+
|
|
27
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
28
|
+
AUGMENT_RULES = ROOT / ".augment" / "rules"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _split_frontmatter(text: str):
|
|
32
|
+
if not text.startswith("---\n"):
|
|
33
|
+
return None
|
|
34
|
+
end = text.find("\n---\n", 4)
|
|
35
|
+
if end == -1:
|
|
36
|
+
return None
|
|
37
|
+
try:
|
|
38
|
+
fm = yaml.safe_load(text[4:end])
|
|
39
|
+
except yaml.YAMLError:
|
|
40
|
+
return None
|
|
41
|
+
return fm if isinstance(fm, dict) else {}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _check_rule(rule_file: Path, misses: list[tuple[str, str]]) -> int:
|
|
45
|
+
fm = _split_frontmatter(rule_file.read_text(encoding="utf-8"))
|
|
46
|
+
if not fm:
|
|
47
|
+
return 0
|
|
48
|
+
checked = 0
|
|
49
|
+
rule_dir = rule_file.parent
|
|
50
|
+
for key in ("load_context", "load_context_eager"):
|
|
51
|
+
entries = fm.get(key) or []
|
|
52
|
+
if not isinstance(entries, list):
|
|
53
|
+
continue
|
|
54
|
+
for entry in entries:
|
|
55
|
+
if not isinstance(entry, str):
|
|
56
|
+
continue
|
|
57
|
+
checked += 1
|
|
58
|
+
target = (rule_dir / entry).resolve()
|
|
59
|
+
if not target.is_file():
|
|
60
|
+
misses.append((str(rule_file.relative_to(ROOT)), entry))
|
|
61
|
+
return checked
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main() -> int:
|
|
65
|
+
if not AUGMENT_RULES.is_dir():
|
|
66
|
+
print(
|
|
67
|
+
f"❌ {AUGMENT_RULES.relative_to(ROOT)} not found — run `task sync` first",
|
|
68
|
+
file=sys.stderr,
|
|
69
|
+
)
|
|
70
|
+
return 3
|
|
71
|
+
|
|
72
|
+
misses: list[tuple[str, str]] = []
|
|
73
|
+
rule_count = 0
|
|
74
|
+
entry_count = 0
|
|
75
|
+
for rule_file in sorted(AUGMENT_RULES.glob("*.md")):
|
|
76
|
+
rule_count += 1
|
|
77
|
+
entry_count += _check_rule(rule_file, misses)
|
|
78
|
+
|
|
79
|
+
if misses:
|
|
80
|
+
print(f"❌ {len(misses)} unresolved load_context entr(y/ies):")
|
|
81
|
+
for rule, entry in misses:
|
|
82
|
+
print(f" {rule} → {entry!r}")
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
print(
|
|
86
|
+
f"✅ smoke-path-resolution clean "
|
|
87
|
+
f"({rule_count} rules, {entry_count} load_context entr(y/ies) resolved)"
|
|
88
|
+
)
|
|
89
|
+
return 0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
sys.exit(main())
|
|
@@ -157,15 +157,55 @@ def _parse_yaml_block(body: str) -> dict[str, Any]:
|
|
|
157
157
|
def _consume_block_list(lines: list[str], start: int) -> tuple[list[Any], int]:
|
|
158
158
|
items: list[Any] = []
|
|
159
159
|
i = start
|
|
160
|
+
item_indent: int | None = None
|
|
160
161
|
while i < len(lines):
|
|
161
162
|
line = lines[i]
|
|
162
163
|
if not line.strip():
|
|
163
164
|
i += 1
|
|
164
165
|
continue
|
|
165
166
|
stripped = line.lstrip()
|
|
167
|
+
leading = len(line) - len(stripped)
|
|
166
168
|
if not stripped.startswith("- "):
|
|
169
|
+
# Out of the list — caller resumes.
|
|
167
170
|
break
|
|
168
|
-
|
|
171
|
+
if item_indent is None:
|
|
172
|
+
item_indent = leading
|
|
173
|
+
elif leading != item_indent:
|
|
174
|
+
break
|
|
175
|
+
item_body = stripped[2:].strip()
|
|
176
|
+
# Inline mapping inside the list: `- key: value`
|
|
177
|
+
m = re.match(r"^([\w-]+):\s*(.*)$", item_body)
|
|
178
|
+
if m:
|
|
179
|
+
mapping: dict[str, Any] = {}
|
|
180
|
+
key = m.group(1)
|
|
181
|
+
raw = m.group(2).strip()
|
|
182
|
+
mapping[key] = _coerce(raw) if raw != "" else ""
|
|
183
|
+
# Consume continuation lines that are indented past the dash —
|
|
184
|
+
# they belong to the same mapping item (`pattern: …`, `reason: …`).
|
|
185
|
+
cont_indent = item_indent + 2 # `- ` is two chars
|
|
186
|
+
i += 1
|
|
187
|
+
while i < len(lines):
|
|
188
|
+
cont = lines[i]
|
|
189
|
+
if not cont.strip():
|
|
190
|
+
i += 1
|
|
191
|
+
continue
|
|
192
|
+
cont_stripped = cont.lstrip()
|
|
193
|
+
cont_leading = len(cont) - len(cont_stripped)
|
|
194
|
+
if cont_stripped.startswith("- "):
|
|
195
|
+
break
|
|
196
|
+
if cont_leading <= item_indent:
|
|
197
|
+
break
|
|
198
|
+
cm = re.match(r"^([\w-]+):\s*(.*)$", cont_stripped)
|
|
199
|
+
if cm and cont_leading >= cont_indent:
|
|
200
|
+
ckey = cm.group(1)
|
|
201
|
+
cval = cm.group(2).strip()
|
|
202
|
+
mapping[ckey] = _coerce(cval) if cval != "" else ""
|
|
203
|
+
i += 1
|
|
204
|
+
else:
|
|
205
|
+
break
|
|
206
|
+
items.append(mapping)
|
|
207
|
+
continue
|
|
208
|
+
items.append(_coerce(item_body))
|
|
169
209
|
i += 1
|
|
170
210
|
return items, i - start
|
|
171
211
|
|
package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# Artifact Engagement Recording — mechanics
|
|
2
|
-
|
|
3
|
-
CLI invocation, privacy contract, failure-mode handling, and "what
|
|
4
|
-
this rule does NOT do" catalog for the
|
|
5
|
-
[`artifact-engagement-recording`](../../../rules/artifact-engagement-recording.md)
|
|
6
|
-
rule. The activation gate, cadence table, and consulted-vs-applied
|
|
7
|
-
definitions live in the rule; this file is the lookup material for
|
|
8
|
-
the actual `telemetry:record` call and the privacy floor.
|
|
9
|
-
|
|
10
|
-
## What to record — id-only, no payload
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
./agent-config telemetry:record \
|
|
14
|
-
--task-id "$TASK_ID" \
|
|
15
|
-
--boundary task \
|
|
16
|
-
--consulted skills:php-coder \
|
|
17
|
-
--consulted skills:eloquent \
|
|
18
|
-
--consulted rules:scope-control \
|
|
19
|
-
--applied skills:php-coder \
|
|
20
|
-
--applied rules:scope-control
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
- `--task-id` — the ticket key (`PROJ-123`) for `/implement-ticket`, or a
|
|
24
|
-
short opaque slug derived from the prompt for `/work`. **Never** a
|
|
25
|
-
branch name, a file path, or a free-text title.
|
|
26
|
-
- `--boundary` — `task` or `phase-step`, matching the cadence in the rule.
|
|
27
|
-
- `--consulted <kind>:<id>` — repeat per artefact. `<kind>` is one of
|
|
28
|
-
`skills`, `rules`, `commands`, `guidelines`, `personas`.
|
|
29
|
-
- `--applied <kind>:<id>` — repeat per artefact actually applied.
|
|
30
|
-
- Exit `0` always when disabled (silent). Exit `1` on schema validation
|
|
31
|
-
failure (rule must NOT swallow this — surface to the user). Exit `2`
|
|
32
|
-
on IO failure.
|
|
33
|
-
|
|
34
|
-
## Privacy contract — what NEVER goes into a record
|
|
35
|
-
|
|
36
|
-
The CLI rejects most violations on the input boundary, but the agent must
|
|
37
|
-
not even attempt these:
|
|
38
|
-
|
|
39
|
-
- ❌ File paths (`src/Foo.php`, `tests/...`) — id fields are
|
|
40
|
-
artefact identifiers only.
|
|
41
|
-
- ❌ Source code, prompt text, ticket body, AC text.
|
|
42
|
-
- ❌ Branch names, commit shas, PR numbers, URLs.
|
|
43
|
-
- ❌ Secrets, env vars, credentials, customer data.
|
|
44
|
-
- ❌ Free-text strings longer than 200 chars (CLI enforces; agent must
|
|
45
|
-
not generate).
|
|
46
|
-
|
|
47
|
-
When in doubt → **don't record**. A missing event is cheap; a leaked
|
|
48
|
-
prompt is not.
|
|
49
|
-
|
|
50
|
-
## Failure modes — DO NOT block the user's task
|
|
51
|
-
|
|
52
|
-
- Schema rejection (CLI exit `1`) → log the message internally, continue
|
|
53
|
-
the user's task. Do **not** halt the dispatch loop.
|
|
54
|
-
- IO failure (CLI exit `2`) → same. The telemetry is **observation**, not
|
|
55
|
-
a delivery requirement.
|
|
56
|
-
- Settings malformed → already handled by the CLI: it falls back to
|
|
57
|
-
disabled and exits `0`. Agent treats it as "disabled this task".
|
|
58
|
-
|
|
59
|
-
The only error the agent surfaces is when the user explicitly asked for
|
|
60
|
-
recording (`telemetry:status` confirms enabled) but no event reached the
|
|
61
|
-
log — that is a real bug, not a swallowed error.
|
|
62
|
-
|
|
63
|
-
## What this rule does NOT do
|
|
64
|
-
|
|
65
|
-
- Run when `enabled: false` (cost floor is zero — see
|
|
66
|
-
[`tests/telemetry/test_cost_floor.py`](../../../../tests/telemetry/test_cost_floor.py)).
|
|
67
|
-
- Track the agent's tool calls, file reads, or token spend — that is
|
|
68
|
-
out of scope, see the roadmap's "out-of-scope" section.
|
|
69
|
-
- Decide retirement. Phase 4's aggregator + report renderer are the only
|
|
70
|
-
consumers that may interpret the JSONL.
|
|
71
|
-
- Run on cloud surfaces (Claude.ai Web, Skills API). The
|
|
72
|
-
`cloud_safe: noop` marker keeps it inert there.
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Augment portability — mechanics
|
|
2
|
-
|
|
3
|
-
`task`-to-script translation table, the `./agent-config` consumer-CLI
|
|
4
|
-
table, and the rationale behind both for the
|
|
5
|
-
[`augment-portability`](../../../rules/augment-portability.md) rule.
|
|
6
|
-
The portability obligation, the agnostic-content rules, and the
|
|
7
|
-
enforcement script reference live in the rule; this file is the
|
|
8
|
-
lookup material when an agent is about to write or edit an artefact
|
|
9
|
-
that mentions a runtime invocation.
|
|
10
|
-
|
|
11
|
-
## Why no `task` commands inside artefacts
|
|
12
|
-
|
|
13
|
-
Skills, rules, commands, guidelines, personas, and context docs
|
|
14
|
-
shipped by this package run in **consumer projects**. Consumer
|
|
15
|
-
projects may not have [Task](https://taskfile.dev) installed —
|
|
16
|
-
they might use npm scripts, Composer scripts, Make, or nothing at
|
|
17
|
-
all. A skill that instructs an agent to run `task <something>`
|
|
18
|
-
silently breaks in every project without a `Taskfile.yml`.
|
|
19
|
-
|
|
20
|
-
Task remains a convenience shortcut for maintainers working on the
|
|
21
|
-
package repo itself — `task ci` is the recommended local gate before
|
|
22
|
-
a PR and lives in `Taskfile.yml`, `AGENTS.md`, and the package README.
|
|
23
|
-
Those maintainer-facing surfaces are outside the scope of this rule.
|
|
24
|
-
Artefact files must assume Task is absent.
|
|
25
|
-
|
|
26
|
-
The detection pattern *"if the consumer has a `Makefile` / build
|
|
27
|
-
script, prefer its targets over raw commands"* is still allowed when
|
|
28
|
-
the skill adapts to the **consumer's own** tooling (e.g.
|
|
29
|
-
`tests-execute` detecting `php artisan test` vs `vendor/bin/pest`).
|
|
30
|
-
It is not allowed to reference `task <name>` as the detected target —
|
|
31
|
-
every direct invocation must resolve to a real script path.
|
|
32
|
-
|
|
33
|
-
## Translation table — `task` → script
|
|
34
|
-
|
|
35
|
-
| ❌ Forbidden | ✅ Portable |
|
|
36
|
-
|---|---|
|
|
37
|
-
| `task sync` | `bash scripts/compress.sh --sync` |
|
|
38
|
-
| `task sync-check` | `bash scripts/compress.sh --check` |
|
|
39
|
-
| `task sync-check-hashes` | `bash scripts/compress.sh --check-hashes` |
|
|
40
|
-
| `task sync-changed` | `bash scripts/compress.sh --changed` |
|
|
41
|
-
| `task sync-mark-done -- X` | `bash scripts/compress.sh --mark-done X` |
|
|
42
|
-
| `task generate-tools` | `python3 scripts/compress.py --generate-tools` |
|
|
43
|
-
| `task lint-skills` | `python3 scripts/skill_linter.py --all` |
|
|
44
|
-
| `task check-refs` | `python3 scripts/check_references.py` |
|
|
45
|
-
| `task check-portability` | `python3 scripts/check_portability.py` |
|
|
46
|
-
| `task check-compression` | `python3 scripts/check_compression.py` |
|
|
47
|
-
| `task validate-schema` | `python3 scripts/validate_frontmatter.py` |
|
|
48
|
-
| `task counts-check` | `python3 scripts/update_counts.py --check` |
|
|
49
|
-
| `task roadmap-progress` | `./agent-config roadmap:progress` |
|
|
50
|
-
| `task ci` | run each underlying script directly (no single portable equivalent) |
|
|
51
|
-
|
|
52
|
-
## Consumer CLI — `./agent-config`
|
|
53
|
-
|
|
54
|
-
A subset of package scripts is exposed through a project-local CLI
|
|
55
|
-
wrapper `./agent-config` (written into the project root by the
|
|
56
|
-
installer, gitignored). Artefacts MUST prefer the CLI over raw
|
|
57
|
-
`python3 scripts/…` paths for every command the CLI already covers,
|
|
58
|
-
because the raw paths only resolve inside the package repo — in a
|
|
59
|
-
consumer project the scripts live under `node_modules/` or `vendor/`.
|
|
60
|
-
|
|
61
|
-
| ❌ Forbidden in artefacts | ✅ Portable |
|
|
62
|
-
|---|---|
|
|
63
|
-
| `python3 scripts/mcp_render.py` | `./agent-config mcp:render` |
|
|
64
|
-
| `python3 scripts/mcp_render.py --check` | `./agent-config mcp:check` |
|
|
65
|
-
| `python3 .augment/scripts/update_roadmap_progress.py` | `./agent-config roadmap:progress` |
|
|
66
|
-
| `python3 .augment/scripts/update_roadmap_progress.py --check` | `./agent-config roadmap:progress-check` |
|
|
67
|
-
| `bash scripts/first-run.sh` | `./agent-config first-run` |
|
|
68
|
-
| `PYTHONPATH=… python3 -m implement_ticket` | `./agent-config implement-ticket` |
|
|
69
|
-
| `python3 scripts/memory_lookup.py` | `./agent-config memory:lookup` |
|
|
70
|
-
| `python3 scripts/memory_signal.py` | `./agent-config memory:signal` |
|
|
71
|
-
| `python3 scripts/memory_hash.py` | `./agent-config memory:hash` |
|
|
72
|
-
| `python3 scripts/check_memory.py` | `./agent-config memory:check` |
|
|
73
|
-
| `python3 scripts/check_memory_proposal.py` | `./agent-config memory:check-proposal` |
|
|
74
|
-
| `python3 scripts/check_proposal.py` | `./agent-config proposal:check` |
|
|
75
|
-
| `python3 scripts/refine_ticket_detect.py` | `./agent-config refine-ticket:detect` |
|
|
76
|
-
|
|
77
|
-
Commands not covered by the CLI stay as direct script invocations
|
|
78
|
-
(e.g. `bash scripts/compress.sh --sync`) — those are maintainer-only
|
|
79
|
-
and not reachable from a consumer project anyway.
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# CLI output handling — mechanics
|
|
2
|
-
|
|
3
|
-
Codebase navigation tips, the redirect-summarize-target fallback
|
|
4
|
-
pattern, the general rules around exit codes / summary lines, and the
|
|
5
|
-
CLI-over-MCP catalog for the
|
|
6
|
-
[`cli-output-handling`](../../../rules/cli-output-handling.md) rule.
|
|
7
|
-
The Iron Law, the detection rule (`rtk_installed`), the verbose-command
|
|
8
|
-
table, and the exceptions list live in the rule; this file is the
|
|
9
|
-
lookup material when the agent has to fall back from `rtk`.
|
|
10
|
-
|
|
11
|
-
## Codebase Navigation
|
|
12
|
-
|
|
13
|
-
### Use what you already have
|
|
14
|
-
|
|
15
|
-
- Edited a file → the edit tool already returned the result. Skip re-reading.
|
|
16
|
-
- Ran a command → you have the output. Skip re-running to "verify".
|
|
17
|
-
- File in context from recent messages → skip reloading.
|
|
18
|
-
- Found a symbol → use it. Skip searching again differently.
|
|
19
|
-
|
|
20
|
-
### Search before reading
|
|
21
|
-
|
|
22
|
-
- **Search first** — `codebase-retrieval`, `search_query_regex`, or `grep`.
|
|
23
|
-
- **Load only what you need** — use `view_range` or `search_query_regex`, not full files.
|
|
24
|
-
- **Small files** (< 50 lines) — OK to read fully.
|
|
25
|
-
|
|
26
|
-
### Ignored files (`.augmentignore`)
|
|
27
|
-
|
|
28
|
-
- `vendor/`, `node_modules/`, lock files, and generated files are excluded from `codebase-retrieval`.
|
|
29
|
-
- When you need to understand a vendor package (base class, interface, API), **read the specific file** with `view`. This bypasses the ignore.
|
|
30
|
-
- Load only the file you need — never browse entire vendor directories.
|
|
31
|
-
|
|
32
|
-
### Minimize tool calls
|
|
33
|
-
|
|
34
|
-
- **Parallel reads** — read multiple files in one batch, not sequentially.
|
|
35
|
-
- **`search_query_regex`** over full file reads.
|
|
36
|
-
- **`view_range`** when you know the exact lines.
|
|
37
|
-
- **One `codebase-retrieval` call** with all symbols — batch, not 5 separate calls.
|
|
38
|
-
|
|
39
|
-
## Fallback Pattern: Redirect, Summarize, Target
|
|
40
|
-
|
|
41
|
-
When `rtk` has no matching subcommand for the tool at hand, fall back to
|
|
42
|
-
this pattern. Every command that MAY produce more than ~30 lines of output:
|
|
43
|
-
|
|
44
|
-
### Step 1: Redirect to file
|
|
45
|
-
```bash
|
|
46
|
-
docker compose exec -T <service> <command> 2>&1 > /tmp/<tool>-output.txt
|
|
47
|
-
echo "EXIT=$?"
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Step 2: Read ONLY the summary
|
|
51
|
-
```bash
|
|
52
|
-
tail -5 /tmp/<tool>-output.txt
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Step 3: If errors exist, read ONLY what you need to fix
|
|
56
|
-
```bash
|
|
57
|
-
grep "ERROR\|error\|✏️" /tmp/<tool>-output.txt | head -20
|
|
58
|
-
grep "app/Services/MyService.php" /tmp/<tool>-output.txt
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**NEVER** do:
|
|
62
|
-
- `cat /tmp/<tool>-output.txt` (loads everything)
|
|
63
|
-
- Read the full output of a passing command (waste)
|
|
64
|
-
- Read diffs you don't plan to act on
|
|
65
|
-
|
|
66
|
-
## General Rules
|
|
67
|
-
|
|
68
|
-
For tool-specific commands → see the `quality-tools` skill.
|
|
69
|
-
|
|
70
|
-
1. **Exit code first**: Check `$?` before reading ANY output. If 0, you're done — skip reading.
|
|
71
|
-
2. **Summary line**: Most tools print a summary as the last few lines. That's all you need.
|
|
72
|
-
3. **Targeted grep**: When you need details, `grep` for the specific file or error type.
|
|
73
|
-
4. **Read once, act, move on**: Once you've read output and acted on it, skip re-reading.
|
|
74
|
-
5. **Iterative fixing**: Fix one error at a time, re-run, check exit code.
|
|
75
|
-
Output becomes stale after each fix — always re-run before reading again.
|
|
76
|
-
|
|
77
|
-
## CLI Over MCP
|
|
78
|
-
|
|
79
|
-
MCP servers are **significantly more token-expensive** than CLI equivalents.
|
|
80
|
-
When both options exist, prefer the CLI tool.
|
|
81
|
-
|
|
82
|
-
- **Git**: `git` CLI, not Git MCP
|
|
83
|
-
- **Files**: shell commands, not filesystem MCP
|
|
84
|
-
- **APIs**: `curl`/`httpie`, not HTTP MCP
|
|
85
|
-
- **Database**: `mysql`/`psql` CLI, not DB MCP
|
|
86
|
-
|
|
87
|
-
Exception: MCPs with **unique capabilities** (Sentry, Playwright, Jira).
|