@event4u/agent-config 1.17.0 → 1.19.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/council/default.md +74 -76
- package/.agent-src/commands/feature/roadmap.md +22 -0
- package/.agent-src/commands/roadmap/create.md +38 -6
- package/.agent-src/commands/roadmap/execute.md +36 -9
- package/.agent-src/rules/agent-authority.md +1 -0
- package/.agent-src/rules/agent-docs.md +1 -0
- package/.agent-src/rules/analysis-skill-routing.md +1 -0
- package/.agent-src/rules/architecture.md +1 -0
- package/.agent-src/rules/artifact-drafting-protocol.md +1 -0
- package/.agent-src/rules/artifact-engagement-recording.md +1 -0
- package/.agent-src/rules/ask-when-uncertain.md +1 -0
- package/.agent-src/rules/augment-portability.md +1 -0
- package/.agent-src/rules/augment-source-of-truth.md +1 -0
- package/.agent-src/rules/autonomous-execution.md +1 -0
- package/.agent-src/rules/capture-learnings.md +1 -0
- package/.agent-src/rules/chat-history-cadence.md +34 -0
- package/.agent-src/rules/chat-history-ownership.md +1 -0
- package/.agent-src/rules/chat-history-visibility.md +1 -0
- package/.agent-src/rules/cli-output-handling.md +2 -2
- package/.agent-src/rules/command-suggestion-policy.md +1 -0
- package/.agent-src/rules/commit-conventions.md +1 -0
- package/.agent-src/rules/commit-policy.md +1 -0
- package/.agent-src/rules/context-hygiene.md +28 -0
- package/.agent-src/rules/direct-answers.md +18 -26
- package/.agent-src/rules/docker-commands.md +1 -0
- package/.agent-src/rules/docs-sync.md +1 -0
- package/.agent-src/rules/downstream-changes.md +1 -0
- package/.agent-src/rules/e2e-testing.md +1 -0
- package/.agent-src/rules/guidelines.md +1 -0
- package/.agent-src/rules/improve-before-implement.md +1 -0
- package/.agent-src/rules/language-and-tone.md +1 -0
- package/.agent-src/rules/laravel-translations.md +1 -0
- package/.agent-src/rules/markdown-safe-codeblocks.md +1 -0
- package/.agent-src/rules/minimal-safe-diff.md +1 -0
- package/.agent-src/rules/missing-tool-handling.md +1 -0
- package/.agent-src/rules/model-recommendation.md +1 -0
- package/.agent-src/rules/no-cheap-questions.md +15 -21
- package/.agent-src/rules/no-roadmap-references.md +1 -0
- package/.agent-src/rules/non-destructive-by-default.md +1 -0
- package/.agent-src/rules/onboarding-gate.md +33 -0
- package/.agent-src/rules/package-ci-checks.md +1 -0
- package/.agent-src/rules/php-coding.md +1 -0
- package/.agent-src/rules/preservation-guard.md +1 -0
- package/.agent-src/rules/review-routing-awareness.md +1 -0
- package/.agent-src/rules/reviewer-awareness.md +1 -0
- package/.agent-src/rules/roadmap-progress-sync.md +49 -0
- package/.agent-src/rules/role-mode-adherence.md +2 -2
- package/.agent-src/rules/rule-type-governance.md +29 -0
- package/.agent-src/rules/runtime-safety.md +1 -0
- package/.agent-src/rules/scope-control.md +1 -0
- package/.agent-src/rules/security-sensitive-stop.md +1 -0
- package/.agent-src/rules/size-enforcement.md +1 -0
- package/.agent-src/rules/skill-improvement-trigger.md +1 -0
- package/.agent-src/rules/skill-quality.md +1 -0
- package/.agent-src/rules/slash-command-routing-policy.md +39 -0
- package/.agent-src/rules/think-before-action.md +1 -0
- package/.agent-src/rules/token-efficiency.md +1 -0
- package/.agent-src/rules/tool-safety.md +1 -0
- package/.agent-src/rules/ui-audit-gate.md +1 -0
- package/.agent-src/rules/upstream-proposal.md +1 -0
- package/.agent-src/rules/user-interaction.md +1 -0
- package/.agent-src/rules/verify-before-complete.md +1 -0
- package/.agent-src/skills/roadmap-management/SKILL.md +29 -4
- package/.agent-src/skills/verify-completion-evidence/SKILL.md +8 -1
- package/.agent-src/templates/agent-settings.md +16 -0
- package/.agent-src/templates/roadmaps.md +12 -3
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +9 -0
- package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +4 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +4 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.py +163 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +111 -0
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +36 -0
- package/.agent-src/templates/scripts/work_engine/scoring/decision_trace.py +141 -0
- package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +125 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +97 -0
- package/README.md +20 -20
- package/config/agent-settings.template.yml +23 -0
- package/docs/architecture.md +1 -1
- package/docs/catalog.md +5 -2
- package/docs/contracts/adr-settings-sync-engine.md +127 -0
- package/docs/contracts/decision-trace-v1.md +146 -0
- package/docs/contracts/file-ownership-matrix.json +7 -0
- package/docs/contracts/hook-architecture-v1.md +213 -0
- package/docs/contracts/load-context-budget-model.md +80 -0
- package/docs/contracts/load-context-schema.md +20 -0
- package/docs/contracts/memory-visibility-v1.md +138 -0
- package/docs/contracts/one-off-script-lifecycle.md +109 -0
- package/docs/contracts/roadmap-complexity-standard.md +137 -0
- package/docs/contracts/rule-interactions.yml +22 -0
- package/docs/customization.md +1 -0
- package/docs/development.md +4 -1
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
- package/docs/guidelines/agent-infra/direct-answers-demos.md +145 -0
- package/docs/guidelines/agent-infra/layered-settings.md +32 -13
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
- package/package.json +1 -1
- package/scripts/agent-config +64 -0
- package/scripts/ai_council/bundler.py +3 -3
- package/scripts/ai_council/clients.py +24 -8
- package/scripts/ai_council/one_off_archive/2026-05/README.md +67 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +206 -0
- package/scripts/ai_council/{_one_off_roundtrip.py → one_off_archive/2026-05/_one_off_roundtrip.py} +13 -8
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +180 -0
- package/scripts/ai_council/session.py +92 -0
- package/scripts/build_rule_trigger_matrix.py +360 -0
- package/scripts/capture_showcase_session.py +361 -0
- package/scripts/chat_history.py +11 -1
- package/scripts/check_always_budget.py +46 -2
- package/scripts/check_one_off_location.py +81 -0
- package/scripts/check_references.py +6 -0
- package/scripts/compress.py +5 -2
- package/scripts/context_hygiene_hook.py +181 -0
- package/scripts/council_cli.py +357 -0
- package/scripts/hook_manifest.yaml +184 -0
- package/scripts/hooks/__init__.py +1 -0
- package/scripts/hooks/augment-context-hygiene.sh +55 -0
- package/scripts/hooks/augment-dispatcher.sh +72 -0
- package/scripts/hooks/augment-onboarding-gate.sh +55 -0
- package/scripts/hooks/cline-dispatcher.sh +86 -0
- package/scripts/hooks/cursor-dispatcher.sh +76 -0
- package/scripts/hooks/dispatch_hook.py +348 -0
- package/scripts/hooks/envelope.py +98 -0
- package/scripts/hooks/gemini-dispatcher.sh +117 -0
- package/scripts/hooks/state_io.py +122 -0
- package/scripts/hooks/windsurf-dispatcher.sh +123 -0
- package/scripts/hooks_status.py +146 -0
- package/scripts/install.py +728 -51
- package/scripts/install.sh +1 -1
- package/scripts/lint_examples.py +98 -0
- package/scripts/lint_hook_manifest.py +216 -0
- package/scripts/lint_one_off_age.py +184 -0
- package/scripts/lint_roadmap_complexity.py +127 -0
- package/scripts/lint_rule_tiers.py +78 -0
- package/scripts/lint_showcase_sessions.py +148 -0
- package/scripts/minimal_safe_diff_hook.py +245 -0
- package/scripts/onboarding_gate_hook.py +142 -0
- package/scripts/readme_linter.py +12 -3
- package/scripts/roadmap_progress_hook.py +5 -0
- package/scripts/schemas/rule.schema.json +5 -0
- package/scripts/sync_agent_settings.py +32 -129
- package/scripts/sync_yaml_rt.py +734 -0
- package/scripts/verify_before_complete_hook.py +216 -0
- /package/scripts/ai_council/{_one_off_2a4_acceptance.py → one_off_archive/2026-05/_one_off_2a4_acceptance.py} +0 -0
- /package/scripts/ai_council/{_one_off_context_layer_v1_estimate.py → one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py} +0 -0
- /package/scripts/ai_council/{_one_off_context_layer_v1_review.py → one_off_archive/2026-05/_one_off_context_layer_v1_review.py} +0 -0
- /package/scripts/ai_council/{_one_off_followups_review.py → one_off_archive/2026-05/_one_off_followups_review.py} +0 -0
- /package/scripts/ai_council/{_one_off_nondestructive_inline_audit.py → one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py} +0 -0
- /package/scripts/{_one_off_phase4_dispatch_latency.py → ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py} +0 -0
- /package/scripts/{_one_off_phase6_trigger_jaccard.py → ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py} +0 -0
- /package/scripts/ai_council/{_one_off_phase_2a_budget_rebalance.py → one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py} +0 -0
- /package/scripts/ai_council/{_one_off_phase_2a_post_revert.py → one_off_archive/2026-05/_one_off_phase_2a_post_revert.py} +0 -0
- /package/scripts/ai_council/{_one_off_rebalancing_audit.py → one_off_archive/2026-05/_one_off_rebalancing_audit.py} +0 -0
- /package/scripts/ai_council/{_one_off_rule_hardening_v1.py → one_off_archive/2026-05/_one_off_rule_hardening_v1.py} +0 -0
- /package/scripts/ai_council/{_one_off_structural_open_questions.py → one_off_archive/2026-05/_one_off_structural_open_questions.py} +0 -0
- /package/scripts/ai_council/{_one_off_structural_optimization.py → one_off_archive/2026-05/_one_off_structural_optimization.py} +0 -0
- /package/scripts/ai_council/{_one_off_structural_v3_gaps.py → one_off_archive/2026-05/_one_off_structural_v3_gaps.py} +0 -0
- /package/scripts/ai_council/{_one_off_structural_v3_review.py → one_off_archive/2026-05/_one_off_structural_v3_review.py} +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Platform-agnostic hook for the `verify-before-complete` rule.
|
|
3
|
+
|
|
4
|
+
Records observable evidence that a verification command (tests, quality
|
|
5
|
+
tools, build) ran. The rule body cites the resulting state file as the
|
|
6
|
+
source of truth for the "have I verified this turn?" question. The hook
|
|
7
|
+
itself never blocks — it is observability infra, not control flow.
|
|
8
|
+
|
|
9
|
+
Wired to multiple events via the manifest:
|
|
10
|
+
- session_start / user_prompt_submit → reset turn-scoped counters
|
|
11
|
+
- post_tool_use → inspect tool + command, record verifications
|
|
12
|
+
- stop → record stop fired (claim-done window)
|
|
13
|
+
|
|
14
|
+
Output: `agents/state/verify-before-complete.json`
|
|
15
|
+
{
|
|
16
|
+
"schema_version": 1,
|
|
17
|
+
"session_id": "<str>",
|
|
18
|
+
"turn_started_at": "<iso8601|null>",
|
|
19
|
+
"last_verification": {"command": ..., "tool": ..., "at": ...} | null,
|
|
20
|
+
"verifications_this_turn": <int>,
|
|
21
|
+
"verifications_this_session": <int>,
|
|
22
|
+
"last_stop_at": "<iso8601|null>",
|
|
23
|
+
"verified_this_turn": <bool>,
|
|
24
|
+
"checked_at": "<iso8601>"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Exit code is always 0.
|
|
28
|
+
"""
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import argparse
|
|
32
|
+
import datetime as _dt
|
|
33
|
+
import json
|
|
34
|
+
import re
|
|
35
|
+
import sys
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
|
|
38
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
39
|
+
from hooks.state_io import atomic_write_json # noqa: E402
|
|
40
|
+
|
|
41
|
+
STATE_FILE = Path("agents") / "state" / "verify-before-complete.json"
|
|
42
|
+
|
|
43
|
+
# Tool names across platforms whose `command` / `tool_input.command` field
|
|
44
|
+
# carries a shell command we can inspect. Edit tools are deliberately
|
|
45
|
+
# excluded — they cannot run verification.
|
|
46
|
+
COMMAND_TOOLS = frozenset({
|
|
47
|
+
"launch-process", "launch_process", # Augment
|
|
48
|
+
"Bash", "BashTool", # Claude Code
|
|
49
|
+
"run-process", "runProcess", # variants
|
|
50
|
+
"shell", "execute_shell", # generic / Cline
|
|
51
|
+
"RunShellCommand", # Cursor
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
# Permissive verification-command pattern. Observability — false positives
|
|
55
|
+
# are cheaper than false negatives. Word-boundary anchored on common
|
|
56
|
+
# shell separators so chained commands (`task sync && task ci`) match.
|
|
57
|
+
_VERIFICATION_RE = re.compile(
|
|
58
|
+
r'(?:^|[\s;&|`(])('
|
|
59
|
+
r'task\s+(?:ci|test|tests|lint|check|qa|phpstan|rector|ecs|pest|pytest)'
|
|
60
|
+
r'|(?:\./|\.venv/bin/|vendor/bin/)?(?:pest|phpunit|phpstan|psalm|rector|ecs)\b'
|
|
61
|
+
r'|(?:python3?|\.venv/bin/python3?)\s+-m\s+pytest'
|
|
62
|
+
r'|pytest\b'
|
|
63
|
+
r'|(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|check|lint|typecheck|tsc)'
|
|
64
|
+
r'|cargo\s+(?:test|check|clippy)'
|
|
65
|
+
r'|go\s+test'
|
|
66
|
+
r'|make\s+(?:test|check|lint)'
|
|
67
|
+
r'|composer\s+(?:test|check|lint|phpstan)'
|
|
68
|
+
r'|(?:php\s+)?artisan\s+test'
|
|
69
|
+
r')',
|
|
70
|
+
re.IGNORECASE,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _now() -> str:
|
|
75
|
+
return _dt.datetime.now(_dt.timezone.utc).isoformat(timespec="seconds")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _empty_state() -> dict:
|
|
79
|
+
return {
|
|
80
|
+
"schema_version": 1,
|
|
81
|
+
"session_id": "",
|
|
82
|
+
"turn_started_at": None,
|
|
83
|
+
"last_verification": None,
|
|
84
|
+
"verifications_this_turn": 0,
|
|
85
|
+
"verifications_this_session": 0,
|
|
86
|
+
"last_stop_at": None,
|
|
87
|
+
"verified_this_turn": False,
|
|
88
|
+
"checked_at": _now(),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _load_state(target: Path) -> dict:
|
|
93
|
+
if not target.is_file():
|
|
94
|
+
return _empty_state()
|
|
95
|
+
try:
|
|
96
|
+
decoded = json.loads(target.read_text(encoding="utf-8"))
|
|
97
|
+
if isinstance(decoded, dict):
|
|
98
|
+
return {**_empty_state(), **decoded}
|
|
99
|
+
except (OSError, json.JSONDecodeError):
|
|
100
|
+
pass
|
|
101
|
+
return _empty_state()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _extract_command(payload: dict) -> tuple[str | None, str | None]:
|
|
105
|
+
"""Return (tool_name, command_text) from a tool-event payload."""
|
|
106
|
+
tool = (payload.get("tool_name") or payload.get("toolName")
|
|
107
|
+
or payload.get("tool"))
|
|
108
|
+
if not isinstance(tool, str) or tool not in COMMAND_TOOLS:
|
|
109
|
+
return (tool if isinstance(tool, str) else None, None)
|
|
110
|
+
ti = payload.get("tool_input")
|
|
111
|
+
if isinstance(ti, dict):
|
|
112
|
+
for key in ("command", "cmd", "shell_command"):
|
|
113
|
+
v = ti.get(key)
|
|
114
|
+
if isinstance(v, str) and v:
|
|
115
|
+
return (tool, v)
|
|
116
|
+
# Some platforms surface the command at the top level.
|
|
117
|
+
for key in ("command", "cmd"):
|
|
118
|
+
v = payload.get(key)
|
|
119
|
+
if isinstance(v, str) and v:
|
|
120
|
+
return (tool, v)
|
|
121
|
+
return (tool, None)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _is_verification(command: str) -> bool:
|
|
125
|
+
return bool(_VERIFICATION_RE.search(command))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _reset_turn(state: dict, session_id: str) -> dict:
|
|
129
|
+
state["session_id"] = session_id or state.get("session_id") or ""
|
|
130
|
+
state["turn_started_at"] = _now()
|
|
131
|
+
state["verifications_this_turn"] = 0
|
|
132
|
+
state["verified_this_turn"] = False
|
|
133
|
+
return state
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _update(state: dict, event: str, envelope: dict) -> dict:
|
|
137
|
+
session_id = envelope.get("session_id") or state.get("session_id") or ""
|
|
138
|
+
if session_id and session_id != state.get("session_id"):
|
|
139
|
+
# Session boundary — reset session-scoped counters.
|
|
140
|
+
state["session_id"] = session_id
|
|
141
|
+
state["verifications_this_session"] = 0
|
|
142
|
+
state = _reset_turn(state, session_id)
|
|
143
|
+
|
|
144
|
+
payload = envelope.get("payload") or {}
|
|
145
|
+
if not isinstance(payload, dict):
|
|
146
|
+
payload = {}
|
|
147
|
+
|
|
148
|
+
if event in ("session_start", "user_prompt_submit"):
|
|
149
|
+
state = _reset_turn(state, session_id)
|
|
150
|
+
elif event == "post_tool_use":
|
|
151
|
+
tool, cmd = _extract_command(payload)
|
|
152
|
+
if cmd and _is_verification(cmd):
|
|
153
|
+
state["last_verification"] = {
|
|
154
|
+
"command": cmd[:512],
|
|
155
|
+
"tool": tool,
|
|
156
|
+
"at": _now(),
|
|
157
|
+
"platform": envelope.get("platform") or "",
|
|
158
|
+
}
|
|
159
|
+
state["verifications_this_turn"] = int(
|
|
160
|
+
state.get("verifications_this_turn") or 0) + 1
|
|
161
|
+
state["verifications_this_session"] = int(
|
|
162
|
+
state.get("verifications_this_session") or 0) + 1
|
|
163
|
+
state["verified_this_turn"] = True
|
|
164
|
+
elif event == "stop":
|
|
165
|
+
state["last_stop_at"] = _now()
|
|
166
|
+
|
|
167
|
+
state["checked_at"] = _now()
|
|
168
|
+
return state
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def run(stdin_text: str, *, consumer_root: Path, verbose: bool = False) -> int:
|
|
172
|
+
envelope: dict = {}
|
|
173
|
+
if stdin_text.strip():
|
|
174
|
+
try:
|
|
175
|
+
decoded = json.loads(stdin_text)
|
|
176
|
+
if isinstance(decoded, dict):
|
|
177
|
+
envelope = decoded
|
|
178
|
+
except json.JSONDecodeError:
|
|
179
|
+
envelope = {}
|
|
180
|
+
|
|
181
|
+
event = envelope.get("event") or ""
|
|
182
|
+
target = consumer_root / STATE_FILE
|
|
183
|
+
state = _load_state(target)
|
|
184
|
+
state = _update(state, event, envelope)
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
atomic_write_json(target, state)
|
|
188
|
+
except OSError:
|
|
189
|
+
if verbose:
|
|
190
|
+
print("verify-before-complete-hook: state write failed",
|
|
191
|
+
file=sys.stderr)
|
|
192
|
+
return 0
|
|
193
|
+
|
|
194
|
+
if verbose:
|
|
195
|
+
print(
|
|
196
|
+
f"verify-before-complete-hook: event={event} "
|
|
197
|
+
f"verified_this_turn={state.get('verified_this_turn')} "
|
|
198
|
+
f"verifications_this_turn={state.get('verifications_this_turn')}",
|
|
199
|
+
file=sys.stderr,
|
|
200
|
+
)
|
|
201
|
+
return 0
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def main(argv: list[str] | None = None) -> int:
|
|
205
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
206
|
+
parser.add_argument("--platform", default="generic",
|
|
207
|
+
help="informational platform tag")
|
|
208
|
+
parser.add_argument("--verbose", action="store_true",
|
|
209
|
+
help="emit one stderr line per invocation")
|
|
210
|
+
args = parser.parse_args(argv)
|
|
211
|
+
return run(sys.stdin.read(), consumer_root=Path.cwd(),
|
|
212
|
+
verbose=args.verbose)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__": # pragma: no cover
|
|
216
|
+
sys.exit(main())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|