@event4u/agent-config 1.18.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 +22 -0
- package/.agent-src/rules/direct-answers.md +1 -0
- 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 +1 -0
- 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 +26 -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 +22 -0
- package/.agent-src/rules/role-mode-adherence.md +2 -2
- package/.agent-src/rules/rule-type-governance.md +1 -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 +8 -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 +62 -0
- package/README.md +19 -19
- package/config/agent-settings.template.yml +23 -0
- 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/memory-visibility-v1.md +138 -0
- package/docs/contracts/one-off-script-lifecycle.md +109 -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/layered-settings.md +32 -13
- package/package.json +1 -1
- package/scripts/agent-config +44 -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 +22 -0
- package/scripts/ai_council/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/capture_showcase_session.py +361 -0
- package/scripts/chat_history.py +11 -1
- package/scripts/check_always_budget.py +7 -2
- package/scripts/context_hygiene_hook.py +14 -6
- 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-dispatcher.sh +72 -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 +725 -87
- package/scripts/install.sh +1 -1
- package/scripts/lint_hook_manifest.py +216 -0
- package/scripts/lint_one_off_age.py +184 -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 +13 -8
- package/scripts/readme_linter.py +12 -3
- package/scripts/roadmap_progress_hook.py +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/README.md
CHANGED
|
@@ -14,13 +14,15 @@ Give your AI agents an audit-disciplined orchestration contract — testing, Git
|
|
|
14
14
|
|
|
15
15
|
## Start here
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Three ways in, depending on what you're doing today:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
| Path | Audience | What it does |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| **[`/onboard`](.agent-src/commands/onboard.md)** | New user, fresh install | Captures name, IDE, rtk, and cost profile; sets `onboarding.onboarded=true` |
|
|
22
|
+
| **[`task ci`](docs/development.md#ci--verification)** | Contributor working **on** this package | Runs the full sync + lint + test pipeline; must be green before push |
|
|
23
|
+
| **[`task generate-tools`](docs/development.md#tool-generation)** | Multi-agent user / consumer project | Rebuilds `.claude/`, `.cursor/`, `.clinerules/`, `.windsurfrules` from the source |
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
If none of those apply yet — start with the [Quickstart](#quickstart) and pick a path once it's installed.
|
|
24
26
|
|
|
25
27
|
## Quickstart
|
|
26
28
|
|
|
@@ -63,6 +65,14 @@ project-locally for all supported AI tools. Task is required for
|
|
|
63
65
|
*contributors* who want to rebuild the compressed content locally — see
|
|
64
66
|
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
65
67
|
|
|
68
|
+
**Verify hook coverage** after installing — every supported platform
|
|
69
|
+
(Augment, Claude, Cursor, Cline, Windsurf, Gemini CLI, Copilot fallback)
|
|
70
|
+
is wired through one universal dispatcher per
|
|
71
|
+
[`hook-architecture-v1`](docs/contracts/hook-architecture-v1.md). Run
|
|
72
|
+
`./agent-config hooks:status` for the matrix (`--strict` for CI,
|
|
73
|
+
`--format json` for tooling). The installer also dry-fires the
|
|
74
|
+
dispatcher per bridge as a post-install smoke test (skip: `--no-smoke`).
|
|
75
|
+
|
|
66
76
|
### For individual use (optional)
|
|
67
77
|
|
|
68
78
|
Install directly in your agent for global, cross-project use:
|
|
@@ -479,20 +489,10 @@ task lint-skills # Lint skills, rules, commands
|
|
|
479
489
|
|
|
480
490
|
## Requirements
|
|
481
491
|
|
|
482
|
-
**
|
|
483
|
-
|
|
484
|
-
- **
|
|
485
|
-
|
|
486
|
-
Available on macOS, Linux, and WSL.
|
|
487
|
-
- **Python 3.10+** — required for the bridge stage only. Pre-installed
|
|
488
|
-
on macOS 12.3+ and all major Linux distros. If missing, the
|
|
489
|
-
orchestrator skips bridges and completes the payload sync.
|
|
490
|
-
- **Composer or npm** — to pull the package itself.
|
|
491
|
-
|
|
492
|
-
**Platform support:** macOS 12.3+, Linux (modern distros), and Windows
|
|
493
|
-
(WSL2) are fully supported. Git Bash works but symlinks require
|
|
494
|
-
Developer Mode; native PowerShell / cmd is not supported. Contributors
|
|
495
|
-
rebuilding `.augment/` locally also need [Task](https://taskfile.dev/).
|
|
492
|
+
- **Bash** — `scripts/install` orchestrates payload sync (`install.sh`) and bridges (`install.py`).
|
|
493
|
+
- **Python 3.10+** — bridge stage only; missing → orchestrator skips bridges.
|
|
494
|
+
- **Composer or npm** — to pull the package.
|
|
495
|
+
- **Platform:** macOS 12.3+, Linux, WSL2. Git Bash needs Developer Mode for symlinks; native PowerShell / cmd unsupported. Contributors rebuilding `.augment/` also need [Task](https://taskfile.dev/).
|
|
496
496
|
|
|
497
497
|
## License
|
|
498
498
|
|
|
@@ -121,6 +121,24 @@ pipelines:
|
|
|
121
121
|
# want a silent agent; `custom` profile ignores this default entirely.
|
|
122
122
|
skill_improvement: true
|
|
123
123
|
|
|
124
|
+
# --- Roadmap execution ---
|
|
125
|
+
#
|
|
126
|
+
# Controls when /roadmap execute runs the project's quality pipeline
|
|
127
|
+
# (the `task ci` / `make test` / `npm run check` style command).
|
|
128
|
+
# Steps are ALWAYS marked `[x]` and the dashboard is ALWAYS regenerated
|
|
129
|
+
# in the same response — that cadence is governed by `roadmap-progress-sync`
|
|
130
|
+
# and is non-negotiable. This setting only governs *quality tool runs*.
|
|
131
|
+
roadmap:
|
|
132
|
+
# When to run quality tools during /roadmap execute.
|
|
133
|
+
# end_of_roadmap = once, before archiving the completed roadmap (default — fastest, fewest tokens)
|
|
134
|
+
# per_phase = once after every completed phase
|
|
135
|
+
# per_step = after every completed step (legacy verbose; highest token cost)
|
|
136
|
+
# Trade-off: end_of_roadmap saves tokens and time but lets errors compound
|
|
137
|
+
# across phases. Pick per_phase if the work is risky or unfamiliar.
|
|
138
|
+
# Iron Law `verify-before-complete` still applies — fresh quality output
|
|
139
|
+
# is mandatory before any "roadmap complete" claim regardless of cadence.
|
|
140
|
+
quality_cadence: end_of_roadmap
|
|
141
|
+
|
|
124
142
|
# --- Subagent orchestration ---
|
|
125
143
|
#
|
|
126
144
|
# Controls model selection and parallelism for subagent-based workflows
|
|
@@ -195,6 +213,11 @@ ai_council:
|
|
|
195
213
|
max_calls: 10
|
|
196
214
|
max_total_usd: 0.50
|
|
197
215
|
|
|
216
|
+
# Retention for `agents/council-sessions/` audit folders. Sessions
|
|
217
|
+
# older than this are pruned automatically on the next `save()`.
|
|
218
|
+
# `0` disables pruning (keep forever — disk grows unbounded).
|
|
219
|
+
session_retention_days: 14
|
|
220
|
+
|
|
198
221
|
# --- Onboarding ---
|
|
199
222
|
#
|
|
200
223
|
# Tracks whether the initial setup flow (/onboard) has been completed
|
package/docs/catalog.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# agent-config — Public Catalog
|
|
2
2
|
|
|
3
|
-
Consumer-facing catalog of all **
|
|
3
|
+
Consumer-facing catalog of all **330 public artefacts** shipped by
|
|
4
4
|
this package. Internal package-maintenance rules and deprecation shims
|
|
5
5
|
are excluded.
|
|
6
6
|
|
|
@@ -301,14 +301,16 @@ are excluded.
|
|
|
301
301
|
| command | [`upstream-contribute`](../.agent-src/commands/upstream-contribute.md) | | Contribute a learning, skill, rule, or fix from a consumer project back to the shared agent-config package |
|
|
302
302
|
| command | [`work`](../.agent-src/commands/work.md) | | Drive a free-form prompt end-to-end through refine → score → plan → implement → test → verify → report — Option-A loop over the `work_engine` Python engine, confidence-band gated, no auto-git. |
|
|
303
303
|
|
|
304
|
-
## Guidelines (
|
|
304
|
+
## Guidelines (51)
|
|
305
305
|
|
|
306
306
|
| kind | name | category | description |
|
|
307
307
|
|---|---|---|---|
|
|
308
308
|
| guideline | [`agent-interaction-and-decision-quality`](../docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md) | agent-infra | |
|
|
309
|
+
| guideline | [`ask-when-uncertain-demos`](../docs/guidelines/agent-infra/ask-when-uncertain-demos.md) | agent-infra | |
|
|
309
310
|
| guideline | [`asking-and-brevity-examples`](../docs/guidelines/agent-infra/asking-and-brevity-examples.md) | agent-infra | |
|
|
310
311
|
| guideline | [`break-glass-usage`](../docs/guidelines/agent-infra/break-glass-usage.md) | agent-infra | |
|
|
311
312
|
| guideline | [`developer-judgment`](../docs/guidelines/agent-infra/developer-judgment.md) | agent-infra | |
|
|
313
|
+
| guideline | [`direct-answers-demos`](../docs/guidelines/agent-infra/direct-answers-demos.md) | agent-infra | |
|
|
312
314
|
| guideline | [`engineering-memory-data-format`](../docs/guidelines/agent-infra/engineering-memory-data-format.md) | agent-infra | |
|
|
313
315
|
| guideline | [`language-and-tone-examples`](../docs/guidelines/agent-infra/language-and-tone-examples.md) | agent-infra | |
|
|
314
316
|
| guideline | [`layered-settings`](../docs/guidelines/agent-infra/layered-settings.md) | agent-infra | |
|
|
@@ -322,6 +324,7 @@ are excluded.
|
|
|
322
324
|
| guideline | [`self-improvement-pipeline`](../docs/guidelines/agent-infra/self-improvement-pipeline.md) | agent-infra | |
|
|
323
325
|
| guideline | [`size-and-scope`](../docs/guidelines/agent-infra/size-and-scope.md) | agent-infra | |
|
|
324
326
|
| guideline | [`tool-integration`](../docs/guidelines/agent-infra/tool-integration.md) | agent-infra | |
|
|
327
|
+
| guideline | [`verify-before-complete-demos`](../docs/guidelines/agent-infra/verify-before-complete-demos.md) | agent-infra | |
|
|
325
328
|
| guideline | [`readme-size-and-splitting`](../docs/guidelines/docs/readme-size-and-splitting.md) | docs | |
|
|
326
329
|
| guideline | [`playwright`](../docs/guidelines/e2e/playwright.md) | e2e | |
|
|
327
330
|
| guideline | [`api-design`](../docs/guidelines/php/api-design.md) | php | |
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ADR — Settings sync engine: stdlib-only round-trip
|
|
6
|
+
|
|
7
|
+
> **Status:** Decided · 2026-05-04
|
|
8
|
+
> **Context:** Additive Settings Sync roadmap — review round 2
|
|
9
|
+
> (Self-Review + AI Council, Anthropic + OpenAI) flagged the
|
|
10
|
+
> 735-line `scripts/sync_yaml_rt.py` as potential NIH burden vs.
|
|
11
|
+
> adopting `ruamel.yaml` as a third-party dependency.
|
|
12
|
+
> **Builds on:** [`docs/guidelines/agent-infra/layered-settings.md`](../guidelines/agent-infra/layered-settings.md)
|
|
13
|
+
> § Sync rules — defines the additive-merge-with-user-line-preservation
|
|
14
|
+
> contract this engine implements.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
`.agent-settings.yml` synchronization uses a **custom, stdlib-only
|
|
19
|
+
round-trip parser + emitter** in [`scripts/sync_yaml_rt.py`](../../scripts/sync_yaml_rt.py),
|
|
20
|
+
not `ruamel.yaml` or any other third-party YAML library.
|
|
21
|
+
|
|
22
|
+
The engine implements a narrow YAML subset (block-mappings, scalars,
|
|
23
|
+
flow-list values, comments, CRLF/LF) that covers the full surface of
|
|
24
|
+
`.agent-settings.yml` plus its template (`config/agent-settings.template.yml`).
|
|
25
|
+
Out-of-subset YAML — anchors, aliases, multi-document streams, complex
|
|
26
|
+
keys, nested flow mappings — is **not supported** and raises `ValueError`.
|
|
27
|
+
|
|
28
|
+
The merge layer (additive walk, max-index insertion, scalar→section
|
|
29
|
+
guard, healer for legacy `_user._user.foo` corruption, EOL
|
|
30
|
+
normalization) sits on top of the parser and is custom regardless of
|
|
31
|
+
the parser choice.
|
|
32
|
+
|
|
33
|
+
## Why this was a real question
|
|
34
|
+
|
|
35
|
+
Three options were on the table:
|
|
36
|
+
|
|
37
|
+
1. **`ruamel.yaml` for parse + emit, custom merge on top.** Rejected.
|
|
38
|
+
2. **`PyYAML` for parse, custom emitter for round-trip.** Rejected
|
|
39
|
+
earlier in the roadmap — PyYAML's parser drops comments and
|
|
40
|
+
formatting before the merger ever sees them.
|
|
41
|
+
3. **Custom stdlib-only parser + emitter + merger.** Chosen.
|
|
42
|
+
|
|
43
|
+
### Why ruamel.yaml does not match the contract
|
|
44
|
+
|
|
45
|
+
The driving requirement from `layered-settings.md` is **verbatim
|
|
46
|
+
user-line preservation** — every byte of every line in the user's
|
|
47
|
+
file is preserved unless that line carries a key the merger is
|
|
48
|
+
explicitly editing. Tests pin this contract by asserting byte-identity
|
|
49
|
+
across two consecutive sync runs (`test_user_block_round_trip_is_idempotent`,
|
|
50
|
+
`test_three_level_idempotent`).
|
|
51
|
+
|
|
52
|
+
`ruamel.yaml` is a round-trip-aware library, not a verbatim one — it
|
|
53
|
+
re-parses into an in-memory model and **re-emits** through its own
|
|
54
|
+
emitter. This re-emit normalizes:
|
|
55
|
+
|
|
56
|
+
| Behavior | ruamel.yaml | Custom engine |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| User-line bytes (whitespace, quoting, blanks) | re-emitted, may shift | preserved 1:1 |
|
|
59
|
+
| Mixed CRLF/LF in user file | normalized to one EOL (typically platform default) | detected + normalized to the user's predominant EOL |
|
|
60
|
+
| `personal: null` blocking template-section injection | requires custom merge logic regardless | scalar guard in `_merge_into` |
|
|
61
|
+
| Legacy `_user._user.foo.bar` healer (one-off migration) | requires custom logic regardless | `heal_user_block` |
|
|
62
|
+
| Synthetic header rendering for newly-inserted template keys | re-emits the entire file | only renders the new subtree |
|
|
63
|
+
| Unknown user blocks at top level | preserved as data, but indent / quoting may shift on emit | preserved verbatim |
|
|
64
|
+
| 3rd-party dependency in distribution package | +1 (`ruamel.yaml` + transitive `ruamel.yaml.clib`) | 0 |
|
|
65
|
+
|
|
66
|
+
The rows where the libraries diverge are exactly the rows the test
|
|
67
|
+
suite asserts on.
|
|
68
|
+
|
|
69
|
+
### Cost analysis
|
|
70
|
+
|
|
71
|
+
| Axis | Custom engine | ruamel.yaml |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| Lines of code | 735 (engine) + 335 (merge/heal) = 1070 | ~400 (parser+emitter saved) + 335 (merge/heal stays) + adapter glue = ~735 |
|
|
74
|
+
| Net code saved | — | ~335 lines |
|
|
75
|
+
| 3rd-party deps | 0 | +2 (`ruamel.yaml`, `ruamel.yaml.clib`) |
|
|
76
|
+
| Runtime YAML surface | narrow (documented subset) | full YAML 1.2 |
|
|
77
|
+
| Verbatim guarantee | yes | no |
|
|
78
|
+
| Performance | irrelevant — cold-path, runs on profile change | irrelevant |
|
|
79
|
+
|
|
80
|
+
The 335-line saving is real but offset by a stronger contract (verbatim)
|
|
81
|
+
and a 0-dep posture. The package is a distribution-layer library
|
|
82
|
+
(`composer.json` `type: library`, `package.json` thin manifest); it
|
|
83
|
+
already restricts itself to stdlib for portability across consumer
|
|
84
|
+
projects, several of which lock Python deps tightly.
|
|
85
|
+
|
|
86
|
+
## Consequences
|
|
87
|
+
|
|
88
|
+
- **Maintenance:** the engine must keep covering the YAML subset its
|
|
89
|
+
template + user files exercise. Any new template feature (e.g. a
|
|
90
|
+
block-style nested list) is a parser change, not a config change.
|
|
91
|
+
- **Error surface:** YAML outside the subset (anchors, complex keys)
|
|
92
|
+
surfaces as a friendly `ValueError` from `_rt.sync()`, caught by
|
|
93
|
+
`sync_agent_settings.main` and turned into exit code 2 with a
|
|
94
|
+
user-readable message. Documented in
|
|
95
|
+
`tests/test_sync_agent_settings.py::test_malformed_user_yaml_exits_2_with_message`.
|
|
96
|
+
- **Test debt:** `tests/test_sync_round_trip.py` (34 tests) and
|
|
97
|
+
`tests/test_sync_agent_settings.py` (15 tests) are the contract.
|
|
98
|
+
Any parser change must keep those green and is the entry point
|
|
99
|
+
for new fixtures under `tests/fixtures/sync_yaml_rt/`.
|
|
100
|
+
|
|
101
|
+
## Revisit triggers
|
|
102
|
+
|
|
103
|
+
This decision is revisited (new ADR with successor link) when **any**
|
|
104
|
+
of the following holds:
|
|
105
|
+
|
|
106
|
+
1. `.agent-settings.yml` schema gains a YAML feature outside the
|
|
107
|
+
supported subset (anchors, multi-doc, complex keys, nested flow
|
|
108
|
+
mappings) — the cost of extending the parser exceeds the cost of
|
|
109
|
+
adopting ruamel.
|
|
110
|
+
2. The verbatim-preservation contract is relaxed (e.g. consumers
|
|
111
|
+
accept that sync can re-format) — the driver for the custom engine
|
|
112
|
+
is gone.
|
|
113
|
+
3. The 0-dep posture for Python tooling is dropped at the package level
|
|
114
|
+
— the marginal cost of one more dep collapses.
|
|
115
|
+
4. A maintenance bug surfaces in the engine that would have been
|
|
116
|
+
prevented by ruamel's mature spec coverage.
|
|
117
|
+
|
|
118
|
+
## See also
|
|
119
|
+
|
|
120
|
+
- [`docs/guidelines/agent-infra/layered-settings.md`](../guidelines/agent-infra/layered-settings.md)
|
|
121
|
+
§ Sync rules — the contract this engine implements.
|
|
122
|
+
- [`scripts/sync_yaml_rt.py`](../../scripts/sync_yaml_rt.py) module
|
|
123
|
+
docstring — the supported YAML subset, listed exhaustively.
|
|
124
|
+
- `tests/test_sync_round_trip.py` — verbatim, scalar-guard, healer,
|
|
125
|
+
CRLF, and synthetic-header pinning.
|
|
126
|
+
- `tests/test_sync_agent_settings.py` — CLI integration, profile
|
|
127
|
+
override, malformed-input exit code.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Decision-trace v1
|
|
6
|
+
|
|
7
|
+
**Purpose.** Pin the JSON shape that `/implement-ticket` and `/work`
|
|
8
|
+
runs emit when the user opts into trace surfacing. The trace is the
|
|
9
|
+
audit substrate for the rule-interaction matrix
|
|
10
|
+
([`rule-interactions.md`](rule-interactions.md)) and feeds the
|
|
11
|
+
showcase-session capture pipeline
|
|
12
|
+
([`outcome-baseline.md`](../../agents/contexts/outcome-baseline.md)).
|
|
13
|
+
|
|
14
|
+
**Scope.** Defines the JSON envelope written next to a `WorkState`
|
|
15
|
+
file when `decision_engine.surface_traces: true`. Does **not**
|
|
16
|
+
specify how individual rules detect their own activation — that is
|
|
17
|
+
the rule's own responsibility — only the shape of the report.
|
|
18
|
+
|
|
19
|
+
Last refreshed: 2026-05-04.
|
|
20
|
+
|
|
21
|
+
## Opt-in
|
|
22
|
+
|
|
23
|
+
Off by default. Toggled in `.agent-settings.yml`:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
decision_engine:
|
|
27
|
+
surface_traces: true
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The `/work` and `/implement-ticket` engines check this flag at phase
|
|
31
|
+
boundaries and emit one trace file per phase when set.
|
|
32
|
+
|
|
33
|
+
## File location
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
agents/state/work/<work-id>/decision-trace-<phase>.json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`work-id` matches the `WorkState` directory; `phase` is one of
|
|
40
|
+
`refine`, `memory`, `analyze`, `plan`, `implement`, `test`, `verify`,
|
|
41
|
+
`report`. Files are gitignored.
|
|
42
|
+
|
|
43
|
+
## Envelope shape
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"schema_version": 1,
|
|
48
|
+
"work_id": "ABCD-1234-2026-05-04T12-34-56Z",
|
|
49
|
+
"phase": "implement",
|
|
50
|
+
"started_at": "2026-05-04T12:35:01Z",
|
|
51
|
+
"ended_at": "2026-05-04T12:38:42Z",
|
|
52
|
+
"confidence_band": "high",
|
|
53
|
+
"risk_class": "low",
|
|
54
|
+
"rules": [
|
|
55
|
+
{
|
|
56
|
+
"rule_id": "verify-before-complete",
|
|
57
|
+
"applied": true,
|
|
58
|
+
"skipped": false,
|
|
59
|
+
"conflicted_with": [],
|
|
60
|
+
"evidence_refs": ["agents/state/work/.../verify.log"]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"memory": {
|
|
64
|
+
"asks": 3,
|
|
65
|
+
"hits": 2,
|
|
66
|
+
"ids": ["mem_42", "mem_57"]
|
|
67
|
+
},
|
|
68
|
+
"verify": {
|
|
69
|
+
"claims": 1,
|
|
70
|
+
"first_try_passes": 1
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Concerns and engines MUST treat unknown top-level keys as forward-
|
|
76
|
+
compat extensions and MUST NOT raise on them.
|
|
77
|
+
|
|
78
|
+
## Field semantics
|
|
79
|
+
|
|
80
|
+
| Field | Meaning |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `schema_version` | Always `1` for this contract. Major bump on breaking changes. |
|
|
83
|
+
| `work_id` | Stable id of the WorkState directory. Allows cross-trace correlation across phases. |
|
|
84
|
+
| `phase` | Engine phase that produced the trace. One of the eight phases above. |
|
|
85
|
+
| `confidence_band` | One of `low` / `medium` / `high`. Heuristic defined below — derived from memory hits + ambiguity flags + verify evidence count. |
|
|
86
|
+
| `risk_class` | One of `low` / `medium` / `high`. Per [`rule-interactions.md`](rule-interactions.md) — drives reviewer routing. |
|
|
87
|
+
| `rules[].rule_id` | Stable rule id, matches the filename under `.agent-src.uncompressed/rules/` minus `.md`. |
|
|
88
|
+
| `rules[].applied` | True if the rule's Iron Law fired and changed engine behaviour this phase. |
|
|
89
|
+
| `rules[].skipped` | True if the rule was checked but produced no effect (no trigger match). |
|
|
90
|
+
| `rules[].conflicted_with` | List of rule_ids that fired against this one. Reduction handled per `rule-interactions.md`. |
|
|
91
|
+
| `rules[].evidence_refs` | Optional list of paths under `agents/state/` or `tests/` that back the `applied` claim. |
|
|
92
|
+
| `memory.asks` | Count of `memory_retrieve` calls during the phase. |
|
|
93
|
+
| `memory.hits` | Count of calls that returned ≥ 1 result. |
|
|
94
|
+
| `memory.ids` | Stable memory entry ids returned. Bounded to ≤ 32 ids per phase; remainder dropped silently. |
|
|
95
|
+
| `verify.claims` | Count of "done"-class claims the engine attempted this phase. |
|
|
96
|
+
| `verify.first_try_passes` | Count of those claims that passed the verify gate without a re-prompt. |
|
|
97
|
+
|
|
98
|
+
## Confidence-band heuristic
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
high: memory.hits ≥ 2 AND verify.first_try_passes == verify.claims AND no ambiguity flag
|
|
102
|
+
medium: memory.hits ≥ 1 OR verify.first_try_passes ≥ 1
|
|
103
|
+
low: otherwise
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Edge case: `verify.claims == 0` is not "high" by default — it folds
|
|
107
|
+
into "medium" if at least one memory hit landed, "low" otherwise.
|
|
108
|
+
|
|
109
|
+
## Risk-class heuristic
|
|
110
|
+
|
|
111
|
+
Mirrors [`file-ownership-matrix.json`](file-ownership-matrix.json):
|
|
112
|
+
the trace inherits the **maximum** risk class across all files the
|
|
113
|
+
phase touched. If no files were touched (pure planning phase), risk
|
|
114
|
+
is `low`.
|
|
115
|
+
|
|
116
|
+
## Privacy floor
|
|
117
|
+
|
|
118
|
+
- `memory.ids` carries opaque ids only — no entry bodies, no secrets.
|
|
119
|
+
- `evidence_refs` carries paths only — no file contents.
|
|
120
|
+
- `rules[].rule_id` is stable id, not free-form text.
|
|
121
|
+
|
|
122
|
+
The visibility line surfaced to the user (Phase 4) consumes this file
|
|
123
|
+
under the same floor.
|
|
124
|
+
|
|
125
|
+
## Stability
|
|
126
|
+
|
|
127
|
+
Beta. Breaking changes between v1 and v2 are allowed in a minor
|
|
128
|
+
release if the change appears in `CHANGELOG.md` under a `### Breaking`
|
|
129
|
+
heading. Engines MUST gate on `schema_version` and refuse unknown
|
|
130
|
+
majors.
|
|
131
|
+
|
|
132
|
+
## Cross-references
|
|
133
|
+
|
|
134
|
+
- Personas (Architect, Risk-Officer) live in the package's persona
|
|
135
|
+
library under [`.agent-src.uncompressed/personas/`](../../.agent-src.uncompressed/personas/).
|
|
136
|
+
This contract does not duplicate them — when a future trace consumer
|
|
137
|
+
attributes a decision to one of those personas, the persona file is
|
|
138
|
+
the source of truth, not this envelope.
|
|
139
|
+
- Rule-interaction matrix:
|
|
140
|
+
[`rule-interactions.md`](rule-interactions.md) (machine-readable
|
|
141
|
+
source: [`rule-interactions.yml`](rule-interactions.yml)).
|
|
142
|
+
- Confidence-band heuristic is implemented in
|
|
143
|
+
`work_engine/scoring/decision_trace.py` and exercised by
|
|
144
|
+
`tests/work_engine/scoring/test_decision_trace_scoring.py`.
|
|
145
|
+
- Outcome metrics consume `verify.first_try_passes`:
|
|
146
|
+
[`outcome-baseline.md`](../../agents/contexts/outcome-baseline.md).
|
|
@@ -6249,6 +6249,13 @@
|
|
|
6249
6249
|
"via": "body_link",
|
|
6250
6250
|
"depth": 1
|
|
6251
6251
|
},
|
|
6252
|
+
{
|
|
6253
|
+
"source": ".agent-src.uncompressed/skills/roadmap-management/SKILL.md",
|
|
6254
|
+
"target": ".agent-src.uncompressed/commands/roadmap/create.md",
|
|
6255
|
+
"type": "READ_ONLY",
|
|
6256
|
+
"via": "body_link",
|
|
6257
|
+
"depth": 1
|
|
6258
|
+
},
|
|
6252
6259
|
{
|
|
6253
6260
|
"source": ".agent-src.uncompressed/skills/roadmap-management/SKILL.md",
|
|
6254
6261
|
"target": ".agent-src.uncompressed/rules/roadmap-progress-sync.md",
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Hook architecture v1
|
|
6
|
+
|
|
7
|
+
**Purpose.** Pin the contract that the universal hook dispatcher
|
|
8
|
+
implements, so concern scripts and per-platform trampolines can be
|
|
9
|
+
written, tested, and refactored against a stable surface.
|
|
10
|
+
|
|
11
|
+
**Scope.** Defines the dispatcher's stdin/stdout shape, exit-code
|
|
12
|
+
semantics, the `hook_manifest.yaml` schema, the concurrency contract
|
|
13
|
+
for `agents/state/` writes, and the Copilot fallback pattern. Does
|
|
14
|
+
**not** specify per-platform install paths — those live in
|
|
15
|
+
[`chat-history-platform-hooks.md`](../../agents/contexts/chat-history-platform-hooks.md).
|
|
16
|
+
|
|
17
|
+
Last refreshed: 2026-05-04.
|
|
18
|
+
|
|
19
|
+
## Vocabulary
|
|
20
|
+
|
|
21
|
+
| Term | Meaning |
|
|
22
|
+
|---|---|
|
|
23
|
+
| **Platform** | Host agent surface — one of `augment`, `claude`, `cursor`, `cline`, `windsurf`, `gemini`, `copilot`. The `claude` value covers both Claude Code (CLI) and Claude.ai Web; the canonical platform identifier is `claude` (matches `chat_history.PLATFORM_EVENT_MAP`). |
|
|
24
|
+
| **Concern** | A single agent-config behaviour wired to one or more lifecycle events — e.g. `chat-history`, `roadmap-progress`, `verify-before-complete`. Lives as a Python script under `scripts/hooks/concerns/<name>.py`. |
|
|
25
|
+
| **Event** | The agent-config-internal event vocabulary the dispatcher exposes — `session_start`, `session_end`, `user_prompt_submit`, `pre_tool_use`, `post_tool_use`, `stop`, `pre_compact`, `agent_error`. Per-platform native names map to these. `agent_error` is synthetic — fired by the agent (or wrapper) when the host crashes outside a concern, so chat-history can checkpoint partial sessions on abnormal exit. (Added in Round 2 — 2026-05-04.) |
|
|
26
|
+
| **Trampoline** | A 5–10 line per-platform shell script that reads the platform's native payload, calls the dispatcher with `--platform <name>`, and forwards the platform's exit-code semantics. |
|
|
27
|
+
| **Dispatcher** | `scripts/hooks/dispatch_hook.py` — single Python entrypoint that reads the manifest, resolves which concerns fire on `(platform, event)`, runs each one with the contract envelope below, and reduces their exit codes. |
|
|
28
|
+
|
|
29
|
+
## Dispatcher invocation
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
python3 scripts/hooks/dispatch_hook.py \
|
|
33
|
+
--platform <name> \
|
|
34
|
+
--event <agent-config-event> \
|
|
35
|
+
[--native-event <platform-event>] \
|
|
36
|
+
< platform-payload.json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`--native-event` is informational; the dispatcher does not branch on
|
|
40
|
+
it. The trampoline is responsible for translating the platform's
|
|
41
|
+
native event name to the agent-config vocabulary before invocation.
|
|
42
|
+
|
|
43
|
+
## Stdin contract — concern envelope
|
|
44
|
+
|
|
45
|
+
The dispatcher writes a single JSON object to each concern's stdin:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"schema_version": 1,
|
|
50
|
+
"platform": "augment",
|
|
51
|
+
"event": "stop",
|
|
52
|
+
"native_event": "Stop",
|
|
53
|
+
"session_id": "…",
|
|
54
|
+
"workspace_root": "/abs/path",
|
|
55
|
+
"payload": { /* opaque, platform-native */ },
|
|
56
|
+
"settings": { /* materialized .agent-settings.yml subset */ }
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Concerns MUST treat unknown top-level keys as forward-compat extensions
|
|
61
|
+
and MUST NOT raise on them. `payload` is passed through verbatim from
|
|
62
|
+
the platform — concerns extract what they need via their own helpers
|
|
63
|
+
(see `scripts/chat_history.py` `_extract_*` for the pattern).
|
|
64
|
+
|
|
65
|
+
## Stdout contract — concern reply
|
|
66
|
+
|
|
67
|
+
A concern MAY write a single JSON object to stdout. The dispatcher
|
|
68
|
+
reads it; non-JSON or empty stdout is treated as no-op (decision
|
|
69
|
+
inferred from exit code only).
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"decision": "allow" | "block" | "warn",
|
|
74
|
+
"reason": "human-readable, ≤ 200 chars",
|
|
75
|
+
"additional_context": "optional — surfaces back to the model on platforms that support it",
|
|
76
|
+
"state_writes": ["agents/state/chat-history.json", "…"]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`state_writes` is advisory; concerns still write the files themselves
|
|
81
|
+
under the concurrency rules below.
|
|
82
|
+
|
|
83
|
+
## Exit-code semantics
|
|
84
|
+
|
|
85
|
+
| Code | Meaning | Dispatcher action |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `0` | allow | no-op; pass through |
|
|
88
|
+
| `1` | block | dispatcher exits 1, surfaces `reason` to platform's deny channel |
|
|
89
|
+
| `2` | warn | dispatcher exits 0, logs `reason` to stderr, sets `additionalContext` if platform supports it |
|
|
90
|
+
| `≥ 3` | error | dispatcher logs full traceback, exits 0 (fail-open) unless `concerns.<name>.fail_closed: true` in settings |
|
|
91
|
+
|
|
92
|
+
## Reduction across multiple concerns
|
|
93
|
+
|
|
94
|
+
When a `(platform, event)` tuple maps to ≥ 2 concerns, the dispatcher
|
|
95
|
+
runs them **sequentially** in manifest order and reduces:
|
|
96
|
+
|
|
97
|
+
- Any `block` → final decision is `block` (most-restrictive merge).
|
|
98
|
+
- Else any `warn` → final decision is `warn`.
|
|
99
|
+
- Else `allow`.
|
|
100
|
+
|
|
101
|
+
`additional_context` strings are concatenated with `\n\n` separators,
|
|
102
|
+
in manifest order. Concerns are never run in parallel — concurrency
|
|
103
|
+
guarantees rely on serial state writes.
|
|
104
|
+
|
|
105
|
+
## Feedback channel — `agents/state/.dispatcher/<session_id>/`
|
|
106
|
+
|
|
107
|
+
Exit-code reduction collapses the severity ladder to a single
|
|
108
|
+
platform-native code, which can hide a `warn` behind a `block` or
|
|
109
|
+
mask non-actioned reasons entirely. To preserve per-concern detail
|
|
110
|
+
without re-routing control flow, the dispatcher writes a feedback
|
|
111
|
+
directory per invocation:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
agents/state/.dispatcher/<session_id>/
|
|
115
|
+
<concern>.json — one file per concern that ran
|
|
116
|
+
summary.json — rollup written after the last concern
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Each `<concern>.json` carries:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"concern": "chat-history",
|
|
124
|
+
"exit_code": 0,
|
|
125
|
+
"raw_exit_code": 0,
|
|
126
|
+
"severity": "allow",
|
|
127
|
+
"decision": "allow",
|
|
128
|
+
"reason": "appended turn 12",
|
|
129
|
+
"duration_ms": 47,
|
|
130
|
+
"started_at": "2026-05-04T12:34:56Z",
|
|
131
|
+
"completed_at": "2026-05-04T12:34:56Z",
|
|
132
|
+
"fail_closed": false
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`summary.json` carries the platform / event tuple, the reduced
|
|
137
|
+
`final_exit_code` + `final_severity`, and a trimmed list of all
|
|
138
|
+
concern entries. `session_id` falls back to
|
|
139
|
+
`dispatch-<unix_ts>-<pid>` when the envelope omits one. Path
|
|
140
|
+
traversal in `session_id` is collapsed (`/`, `\`, `..` → `_`).
|
|
141
|
+
|
|
142
|
+
Feedback writes are non-fatal — IO errors log to stderr but never
|
|
143
|
+
change the dispatcher's exit code. The directory is gitignored and
|
|
144
|
+
consumed by `task hooks-status` (Phase 7.11). Added in Round 2
|
|
145
|
+
(2026-05-04) per Q1 of `tmp/council_round2/q1_feedback_channel.md`.
|
|
146
|
+
|
|
147
|
+
## Manifest schema — `scripts/hook_manifest.yaml`
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
schema_version: 1
|
|
151
|
+
concerns:
|
|
152
|
+
chat-history:
|
|
153
|
+
script: scripts/hooks/concerns/chat_history.py
|
|
154
|
+
fail_closed: false
|
|
155
|
+
roadmap-progress:
|
|
156
|
+
script: scripts/hooks/concerns/roadmap_progress.py
|
|
157
|
+
fail_closed: false
|
|
158
|
+
|
|
159
|
+
platforms:
|
|
160
|
+
augment:
|
|
161
|
+
session_start: [chat-history]
|
|
162
|
+
stop: [chat-history, roadmap-progress]
|
|
163
|
+
post_tool_use: [chat-history]
|
|
164
|
+
claude:
|
|
165
|
+
session_start: [chat-history]
|
|
166
|
+
user_prompt_submit: [chat-history]
|
|
167
|
+
stop: [chat-history, roadmap-progress]
|
|
168
|
+
copilot:
|
|
169
|
+
# No dispatcher — see "Copilot fallback" below.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Validated by `scripts/lint_hook_manifest.py` (Phase 7.10): every
|
|
173
|
+
concern script must exist on disk, every platform key must be a known
|
|
174
|
+
platform, every event key must be in the agent-config event vocabulary.
|
|
175
|
+
|
|
176
|
+
## Concurrency — atomic state writes
|
|
177
|
+
|
|
178
|
+
Concerns that write under `agents/state/` MUST use the pattern:
|
|
179
|
+
|
|
180
|
+
1. Acquire `fcntl.flock(LOCK_EX)` on `agents/state/.dispatcher.lock`.
|
|
181
|
+
2. Write to a sibling `<dest>.tmp.<pid>` file in the same directory.
|
|
182
|
+
3. `os.replace(tmp, dest)` — POSIX-atomic on the same filesystem.
|
|
183
|
+
4. Release the lock.
|
|
184
|
+
|
|
185
|
+
The single `.dispatcher.lock` is intentional: serialising state
|
|
186
|
+
writes across concerns is cheaper than per-file locks, and concerns
|
|
187
|
+
already run sequentially within one dispatcher invocation. The lock
|
|
188
|
+
file is gitignored.
|
|
189
|
+
|
|
190
|
+
Phase 7.4 ships a regression test that spawns two concurrent
|
|
191
|
+
dispatcher invocations against the same event and asserts no torn
|
|
192
|
+
writes (file ends with valid JSON, last-writer-wins).
|
|
193
|
+
|
|
194
|
+
## Copilot fallback pattern
|
|
195
|
+
|
|
196
|
+
Copilot has no hook surface. Concerns whose source rule cites
|
|
197
|
+
`agents/state/<concern>.json` MUST gain a "Copilot fallback" section
|
|
198
|
+
that:
|
|
199
|
+
|
|
200
|
+
- Names the state file the concern would have written.
|
|
201
|
+
- Names a manual command or task that reproduces the side effect
|
|
202
|
+
(e.g. `task chat-history:append`).
|
|
203
|
+
- Includes no Iron-Law-changing prose.
|
|
204
|
+
|
|
205
|
+
The dispatcher silently no-ops when called with `--platform copilot`;
|
|
206
|
+
the fallback is consumed by reading the rule, not by hook invocation.
|
|
207
|
+
|
|
208
|
+
## Stability
|
|
209
|
+
|
|
210
|
+
Beta. Breaking changes between v1 and v2 are allowed in a minor
|
|
211
|
+
release if the change appears in `CHANGELOG.md` under a `### Breaking`
|
|
212
|
+
heading. Concerns MUST gate on `schema_version` and refuse unknown
|
|
213
|
+
majors.
|