@event4u/agent-config 1.18.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/.agent-src/commands/agent-handoff.md +14 -10
  2. package/.agent-src/commands/chat-history/import.md +170 -0
  3. package/.agent-src/commands/chat-history/learn.md +178 -0
  4. package/.agent-src/commands/chat-history/show.md +17 -18
  5. package/.agent-src/commands/chat-history.md +26 -25
  6. package/.agent-src/commands/council/default.md +77 -82
  7. package/.agent-src/commands/create-pr.md +28 -8
  8. package/.agent-src/commands/feature/roadmap.md +22 -0
  9. package/.agent-src/commands/roadmap/create.md +38 -6
  10. package/.agent-src/commands/roadmap/execute.md +36 -9
  11. package/.agent-src/commands/sync-gitignore.md +1 -1
  12. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +76 -0
  13. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +3 -3
  14. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +5 -12
  15. package/.agent-src/rules/agent-authority.md +1 -0
  16. package/.agent-src/rules/agent-docs.md +1 -0
  17. package/.agent-src/rules/analysis-skill-routing.md +1 -0
  18. package/.agent-src/rules/architecture.md +1 -0
  19. package/.agent-src/rules/artifact-drafting-protocol.md +1 -0
  20. package/.agent-src/rules/artifact-engagement-recording.md +1 -0
  21. package/.agent-src/rules/ask-when-uncertain.md +1 -0
  22. package/.agent-src/rules/augment-portability.md +1 -0
  23. package/.agent-src/rules/augment-source-of-truth.md +1 -0
  24. package/.agent-src/rules/autonomous-execution.md +1 -0
  25. package/.agent-src/rules/capture-learnings.md +1 -0
  26. package/.agent-src/rules/cli-output-handling.md +2 -2
  27. package/.agent-src/rules/command-suggestion-policy.md +1 -0
  28. package/.agent-src/rules/commit-conventions.md +1 -0
  29. package/.agent-src/rules/commit-policy.md +1 -0
  30. package/.agent-src/rules/context-hygiene.md +22 -0
  31. package/.agent-src/rules/direct-answers.md +11 -2
  32. package/.agent-src/rules/docker-commands.md +1 -0
  33. package/.agent-src/rules/docs-sync.md +1 -0
  34. package/.agent-src/rules/downstream-changes.md +1 -0
  35. package/.agent-src/rules/e2e-testing.md +1 -0
  36. package/.agent-src/rules/guidelines.md +1 -0
  37. package/.agent-src/rules/improve-before-implement.md +1 -0
  38. package/.agent-src/rules/language-and-tone.md +38 -6
  39. package/.agent-src/rules/laravel-translations.md +1 -0
  40. package/.agent-src/rules/markdown-safe-codeblocks.md +1 -0
  41. package/.agent-src/rules/minimal-safe-diff.md +1 -0
  42. package/.agent-src/rules/missing-tool-handling.md +1 -0
  43. package/.agent-src/rules/model-recommendation.md +1 -0
  44. package/.agent-src/rules/no-attribution-footers.md +48 -0
  45. package/.agent-src/rules/no-cheap-questions.md +1 -0
  46. package/.agent-src/rules/no-roadmap-references.md +2 -1
  47. package/.agent-src/rules/non-destructive-by-default.md +1 -0
  48. package/.agent-src/rules/onboarding-gate.md +26 -0
  49. package/.agent-src/rules/package-ci-checks.md +1 -0
  50. package/.agent-src/rules/php-coding.md +1 -0
  51. package/.agent-src/rules/preservation-guard.md +1 -0
  52. package/.agent-src/rules/review-routing-awareness.md +1 -0
  53. package/.agent-src/rules/reviewer-awareness.md +1 -0
  54. package/.agent-src/rules/roadmap-progress-sync.md +22 -0
  55. package/.agent-src/rules/role-mode-adherence.md +2 -2
  56. package/.agent-src/rules/rule-type-governance.md +1 -0
  57. package/.agent-src/rules/runtime-safety.md +1 -0
  58. package/.agent-src/rules/scope-control.md +1 -0
  59. package/.agent-src/rules/security-sensitive-stop.md +1 -0
  60. package/.agent-src/rules/size-enforcement.md +1 -0
  61. package/.agent-src/rules/skill-improvement-trigger.md +1 -0
  62. package/.agent-src/rules/skill-quality.md +50 -0
  63. package/.agent-src/rules/slash-command-routing-policy.md +39 -0
  64. package/.agent-src/rules/think-before-action.md +1 -0
  65. package/.agent-src/rules/token-efficiency.md +1 -0
  66. package/.agent-src/rules/tool-safety.md +1 -0
  67. package/.agent-src/rules/ui-audit-gate.md +1 -0
  68. package/.agent-src/rules/upstream-proposal.md +1 -0
  69. package/.agent-src/rules/user-interaction.md +22 -5
  70. package/.agent-src/rules/verify-before-complete.md +1 -0
  71. package/.agent-src/skills/ai-council/SKILL.md +4 -5
  72. package/.agent-src/skills/dcf-modeling/SKILL.md +89 -0
  73. package/.agent-src/skills/funnel-analysis/SKILL.md +100 -0
  74. package/.agent-src/skills/md-language-check/SKILL.md +1 -1
  75. package/.agent-src/skills/okr-tree-modeling/SKILL.md +93 -0
  76. package/.agent-src/skills/rice-prioritization/SKILL.md +100 -0
  77. package/.agent-src/skills/roadmap-management/SKILL.md +29 -4
  78. package/.agent-src/skills/subagent-orchestration/SKILL.md +34 -2
  79. package/.agent-src/skills/unit-economics-modeling/SKILL.md +104 -0
  80. package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -0
  81. package/.agent-src/skills/verify-completion-evidence/SKILL.md +8 -1
  82. package/.agent-src/templates/agent-settings.md +21 -26
  83. package/.agent-src/templates/roadmaps.md +8 -3
  84. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +16 -5
  85. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +4 -4
  86. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +4 -4
  87. package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +7 -51
  88. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +1 -2
  89. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +1 -2
  90. package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.py +163 -0
  91. package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +110 -0
  92. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +36 -0
  93. package/.agent-src/templates/scripts/work_engine/scoring/decision_trace.py +141 -0
  94. package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +125 -0
  95. package/.agent-src/templates/skill.md +30 -1
  96. package/.claude-plugin/marketplace.json +8 -4
  97. package/AGENTS.md +44 -3
  98. package/CHANGELOG.md +173 -0
  99. package/README.md +22 -22
  100. package/config/agent-settings.template.yml +42 -13
  101. package/config/gitignore-block.txt +4 -4
  102. package/docs/architecture.md +3 -3
  103. package/docs/catalog.md +18 -13
  104. package/docs/contracts/adr-chat-history-split.md +10 -1
  105. package/docs/contracts/adr-settings-sync-engine.md +127 -0
  106. package/docs/contracts/command-clusters.md +1 -1
  107. package/docs/contracts/cross-wing-handoff.md +133 -0
  108. package/docs/contracts/decision-trace-v1.md +146 -0
  109. package/docs/contracts/file-ownership-matrix.json +348 -126
  110. package/docs/contracts/hook-architecture-v1.md +220 -0
  111. package/docs/contracts/memory-visibility-v1.md +122 -0
  112. package/docs/contracts/one-off-script-lifecycle.md +109 -0
  113. package/docs/contracts/rule-interactions.yml +22 -0
  114. package/docs/customization.md +2 -1
  115. package/docs/development.md +4 -1
  116. package/docs/getting-started.md +21 -29
  117. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +1 -1
  118. package/docs/guidelines/agent-infra/layered-settings.md +32 -13
  119. package/docs/hook-payload-capture.md +221 -0
  120. package/docs/migrations/commands-1.15.0.md +17 -12
  121. package/docs/skills-catalog.md +5 -4
  122. package/llms.txt +4 -3
  123. package/package.json +1 -1
  124. package/scripts/agent-config +45 -1
  125. package/scripts/ai_council/_default_prices.py +4 -4
  126. package/scripts/ai_council/bundler.py +3 -3
  127. package/scripts/ai_council/clients.py +25 -9
  128. package/scripts/ai_council/modes.py +3 -4
  129. package/scripts/ai_council/one_off_archive/2026-05/README.md +22 -0
  130. package/scripts/ai_council/one_off_archive/2026-05/_one_off_roundtrip.py +13 -8
  131. package/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +180 -0
  132. package/scripts/ai_council/pricing.py +10 -9
  133. package/scripts/ai_council/session.py +92 -0
  134. package/scripts/build_rule_trigger_matrix.py +1 -9
  135. package/scripts/capture_showcase_session.py +361 -0
  136. package/scripts/chat_history.py +963 -597
  137. package/scripts/check_always_budget.py +7 -2
  138. package/scripts/check_references.py +12 -2
  139. package/scripts/context_hygiene_hook.py +14 -6
  140. package/scripts/council_cli.py +407 -0
  141. package/scripts/hook_manifest.yaml +217 -0
  142. package/scripts/hooks/__init__.py +1 -0
  143. package/scripts/hooks/augment-chat-history.sh +10 -0
  144. package/scripts/hooks/augment-dispatcher.sh +72 -0
  145. package/scripts/hooks/cline-dispatcher.sh +86 -0
  146. package/scripts/hooks/cowork-dispatcher.sh +98 -0
  147. package/scripts/hooks/cursor-dispatcher.sh +76 -0
  148. package/scripts/hooks/dispatch_hook.py +383 -0
  149. package/scripts/hooks/envelope.py +98 -0
  150. package/scripts/hooks/gemini-dispatcher.sh +117 -0
  151. package/scripts/hooks/state_io.py +122 -0
  152. package/scripts/hooks/windsurf-dispatcher.sh +123 -0
  153. package/scripts/hooks_status.py +157 -0
  154. package/scripts/install-hooks.sh +2 -2
  155. package/scripts/install.py +725 -87
  156. package/scripts/install.sh +38 -1
  157. package/scripts/lint_handoffs.py +214 -0
  158. package/scripts/lint_hook_manifest.py +217 -0
  159. package/scripts/lint_one_off_age.py +184 -0
  160. package/scripts/lint_rule_tiers.py +78 -0
  161. package/scripts/lint_showcase_sessions.py +148 -0
  162. package/scripts/minimal_safe_diff_hook.py +245 -0
  163. package/scripts/onboarding_gate_hook.py +13 -8
  164. package/scripts/readme_linter.py +12 -3
  165. package/scripts/redact_hook_capture.py +148 -0
  166. package/scripts/roadmap_progress_hook.py +5 -0
  167. package/scripts/schemas/skill.schema.json +5 -0
  168. package/scripts/skill_linter.py +163 -1
  169. package/scripts/sync_agent_settings.py +32 -129
  170. package/scripts/sync_yaml_rt.py +734 -0
  171. package/scripts/update_prices.py +3 -3
  172. package/scripts/verify_before_complete_hook.py +216 -0
  173. package/.agent-src/commands/chat-history/checkpoint.md +0 -126
  174. package/.agent-src/commands/chat-history/clear.md +0 -103
  175. package/.agent-src/commands/chat-history/resume.md +0 -183
  176. package/.agent-src/rules/chat-history-cadence.md +0 -109
  177. package/.agent-src/rules/chat-history-ownership.md +0 -123
  178. package/.agent-src/rules/chat-history-visibility.md +0 -96
  179. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +0 -50
  180. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +0 -49
  181. package/scripts/check_phase_coupling.py +0 -148
@@ -0,0 +1,220 @@
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`, `cowork`, `cursor`, `cline`, `windsurf`, `gemini`, `copilot`. The `claude` value covers both Claude Code (CLI) and Claude.ai Web; `cowork` covers the Claude desktop app's local-agent-mode runtime separately so chat-history entries can attribute events to Cowork vs CLI Claude Code via the `agent` field. Cowork shares Claude Code's lifecycle vocabulary and payload shape but is upstream-blocked from reading any settings source as of writing (anthropics/claude-code#40495, #27398). The canonical platform identifier is `claude` for the CLI/IDE surface and `cowork` for the desktop sandbox (both match `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.
214
+
215
+ ## See also
216
+
217
+ - [`docs/hook-payload-capture.md`](../hook-payload-capture.md) —
218
+ operational how-to for capturing redacted live payloads to upgrade
219
+ a platform's chat-history extractor from `docs-verified` to
220
+ `payload-verified`.
@@ -0,0 +1,122 @@
1
+ ---
2
+ stability: beta
3
+ ---
4
+
5
+ # Memory-visibility v1
6
+
7
+ **Purpose.** Pin the format of the user-facing visibility line that
8
+ every memory-using `/work` and `/implement-ticket` run prints, so the
9
+ user can tell what the agent retrieved and what it ignored.
10
+ Complements [`agent-memory-contract.md`](agent-memory-contract.md):
11
+ that doc describes the **CLI surface and backend states**; this doc
12
+ describes the **operator-facing surface** the engine emits per turn.
13
+
14
+ **Scope.** Defines the line shape, the privacy floor, and the opt-out
15
+ toggle. Does **not** define how memory entries are scored or routed —
16
+ that is the sibling agent-memory package.
17
+
18
+ Last refreshed: 2026-05-04.
19
+
20
+ ## Line shape
21
+
22
+ A single one-line ASCII record, prefixed with the memory icon `🧠`
23
+ and a single space:
24
+
25
+ ```
26
+ 🧠 Memory: <hits>/<asks> · ids=[<comma-separated-ids>]
27
+ ```
28
+
29
+ Examples:
30
+
31
+ ```
32
+ 🧠 Memory: 3/4 · ids=[mem_42, mem_57, mem_91]
33
+ 🧠 Memory: 0/2 · ids=[]
34
+ 🧠 Memory: 5/5 · ids=[mem_a01, mem_a02, mem_a03, …+2]
35
+ ```
36
+
37
+ Cap at 5 ids inline; remainder rendered as `…+N`. The full id list
38
+ lives in the decision-trace JSON
39
+ ([`decision-trace-v1.md`](decision-trace-v1.md)).
40
+
41
+ ## Field semantics
42
+
43
+ | Field | Meaning |
44
+ |---|---|
45
+ | `hits` | Count of `memory_retrieve_*` calls during this turn that returned ≥ 1 entry. |
46
+ | `asks` | Count of `memory_retrieve_*` calls during this turn — both successful and empty. |
47
+ | `ids` | Stable memory entry ids returned across all calls, deduped, ordered by retrieval timestamp. |
48
+
49
+ `hits ≤ asks` is invariant. If `asks == 0`, the engine MUST suppress
50
+ the line entirely — no `0/0` noise.
51
+
52
+ ## Privacy floor
53
+
54
+ The visibility line and the JSON it derives from MUST NOT contain:
55
+
56
+ - Entry **bodies**, summaries, or quoted snippets.
57
+ - Secrets, tokens, environment values, or paths outside the
58
+ package's `agents/state/` and `tests/` allowlist.
59
+ - User identifiers beyond what is already public in the working
60
+ directory's `.agent-settings.yml` (e.g. developer name).
61
+
62
+ The privacy floor is enforced by
63
+ `tests/contracts/test_memory_visibility_redaction.py` — any new
64
+ content path that ships memory output adds a fixture there.
65
+
66
+ ## Opt-out
67
+
68
+ On by default whenever memory is asked at all in a turn. Users can
69
+ suppress the visibility line via:
70
+
71
+ ```yaml
72
+ memory:
73
+ visibility: off
74
+ ```
75
+
76
+ Off-mode does not silence the underlying memory calls; it only stops
77
+ the line from rendering. The decision-trace JSON still records the
78
+ counts and ids for downstream metrics.
79
+
80
+ ## Cadence interaction
81
+
82
+ | Cost profile | Visibility line |
83
+ |---|---|
84
+ | `lean` | suppress unless `asks ≥ 3` |
85
+ | `standard` | always when `asks ≥ 1` |
86
+ | `verbose` | always when `asks ≥ 1` |
87
+
88
+ Cost-profile lookup respects `.agent-settings.yml`'s `cost_profile`
89
+ key. Default is `standard`.
90
+
91
+ ## Audit-as-memory feed
92
+
93
+ The visibility output produced by the engine is the input to the
94
+ audit-as-memory pipeline (consumed by the sibling distribution +
95
+ adoption work). Concretely:
96
+
97
+ - The engine emits the line + the underlying counts to the
98
+ decision-trace JSON.
99
+ - A consumer hook reads `agents/state/work/<work-id>/decision-trace-*.json`,
100
+ rolls counts up to the session level, and feeds the result back
101
+ into the agent-memory store as an audit entry.
102
+
103
+ This contract pins the **producer** side. The audit-feed consumer
104
+ lives outside the package's stable surface and must read this
105
+ contract before parsing.
106
+
107
+ ## Stability
108
+
109
+ Beta. Breaking changes between v1 and v2 are allowed in a minor
110
+ release if the change appears in `CHANGELOG.md` under a `### Breaking`
111
+ heading. Engines MUST gate on the visibility line shape — clients
112
+ parsing the stream MUST treat unknown trailing fields as forward-
113
+ compat extensions.
114
+
115
+ ## Cross-references
116
+
117
+ - CLI surface and backend states:
118
+ [`agent-memory-contract.md`](agent-memory-contract.md).
119
+ - Decision-trace JSON consumes the same counts:
120
+ [`decision-trace-v1.md`](decision-trace-v1.md).
121
+ - Privacy regression test path:
122
+ `tests/contracts/test_memory_visibility_redaction.py`.
@@ -0,0 +1,109 @@
1
+ ---
2
+ stability: beta
3
+ ---
4
+
5
+ # One-off-script lifecycle
6
+
7
+ **Purpose.** Pin the naming, location, age, and purge policy for
8
+ **one-off scripts** so the package does not accumulate a graveyard
9
+ under `scripts/`. One-off here means: a script written for a
10
+ specific migration, retrofit, audit, or council run, with no ongoing
11
+ caller and no place in the durable Taskfile.
12
+
13
+ **Scope.** Defines the file pattern, the directory, the maximum age,
14
+ the TTL extension mechanism, and the CI purge gate. Does **not**
15
+ specify the content of any specific one-off — that belongs to the
16
+ script itself or the cleanup-mechanics context.
17
+
18
+ Last refreshed: 2026-05-04.
19
+
20
+ ## Naming
21
+
22
+ One-off scripts MUST match this regex:
23
+
24
+ ```
25
+ ^_one_off_[a-z0-9-]+\.py$
26
+ ```
27
+
28
+ The `_one_off_` prefix is the load-bearing signal. Files outside
29
+ this prefix are treated as durable scripts and MUST be referenced by
30
+ the Taskfile or by another script.
31
+
32
+ ## Location
33
+
34
+ ```
35
+ scripts/_one_off/<YYYY-MM>/_one_off_<slug>.py
36
+ ```
37
+
38
+ `<YYYY-MM>` is the UTC month the script was first committed. The
39
+ month directory groups one-offs for archival sweeps. Scripts MUST
40
+ NOT live at `scripts/_one_off/_one_off_*.py` (no month) or under
41
+ `scripts/` directly (no `_one_off/`).
42
+
43
+ ## TTL
44
+
45
+ | State | Action |
46
+ |---|---|
47
+ | Age ≤ 60 days from month-directory date | active, no warning |
48
+ | 60 < Age ≤ 90 days | warning emitted by `lint_one_off_age.py`, no failure |
49
+ | Age > 90 days | `lint_one_off_age.py` fails CI; the script is purged in the next housekeeping pass |
50
+
51
+ Age = `today − first-of-month(<YYYY-MM>)` in UTC days. The 60-day
52
+ soft floor and 30-day grace window are intentional — they cover one
53
+ release cycle plus a sprint of grace.
54
+
55
+ ## TTL extension
56
+
57
+ A one-off MAY extend its TTL exactly once, by adding a frontmatter
58
+ block at the top of the script:
59
+
60
+ ```python
61
+ """
62
+ ---
63
+ ttl_extended_until: 2026-08-31
64
+ ttl_reason: blocked on PROJ-123 — re-runs after cutover
65
+ ---
66
+ """
67
+ ```
68
+
69
+ The linter respects `ttl_extended_until` if it is ≤ 180 days from
70
+ the file's `<YYYY-MM>` directory date. Beyond 180 days, the linter
71
+ hard-fails — no second extension. The intent is: if a "one-off" is
72
+ still live at six months, it is a durable concern and belongs in
73
+ `scripts/` or a Taskfile group.
74
+
75
+ ## Purge mechanism
76
+
77
+ `lint_one_off_age.py` runs in `task ci`. On a clean working tree, it
78
+ prints purge candidates as a list. Purge itself is a separate human-
79
+ or-CI action — `task purge-one-offs` removes flagged files. The
80
+ linter does not auto-delete.
81
+
82
+ ## Allowed exceptions
83
+
84
+ Two patterns are exempt from the prefix requirement:
85
+
86
+ - **Bundler / orchestrator helpers** under `scripts/ai_council/`
87
+ that exist to support the council CLI — they are not one-offs even
88
+ though council *runs* are one-offs.
89
+ - **`scripts/_one_off/<YYYY-MM>/README.md`** — a free-form readme is
90
+ allowed in each month directory documenting why the scripts exist.
91
+
92
+ Council run scripts that wrap a question and write the response file
93
+ DO live under `scripts/_one_off/<YYYY-MM>/` and DO follow the prefix
94
+ rule.
95
+
96
+ ## Cross-references
97
+
98
+ - The contract that defines council CLI surface (and so what gets
99
+ archived as a one-off): the council CLI section of the package's
100
+ command catalog.
101
+ - The cleanup-mechanics context for housekeeping passes:
102
+ `agents/contexts/cleanup-mechanics.md`.
103
+ - Linter implementation: `scripts/lint_one_off_age.py`.
104
+
105
+ ## Stability
106
+
107
+ Beta. Breaking changes (e.g. raising the age cap, changing the
108
+ prefix, or removing TTL extensions) require a minor-version bump and
109
+ a `### Breaking` entry in `CHANGELOG.md`.
@@ -221,6 +221,28 @@ pairs:
221
221
  - .agent-src.uncompressed/rules/ask-when-uncertain.md#iron-law--one-question-per-turn-always
222
222
  - .agent-src.uncompressed/rules/direct-answers.md#iron-law-3--brevity-by-default
223
223
 
224
+ - id: scope-x-verify-before-complete
225
+ rules: [verify-before-complete, scope-control]
226
+ relation: complements
227
+ conflict: >-
228
+ Agent has just finished a change that touches user-permission-gated
229
+ operations (push, branch, PR, tag) and is preparing to claim "done"
230
+ in the same turn. Both rules can fire: `verify-before-complete`
231
+ gates the completion claim on fresh evidence; `scope-control`
232
+ gates the git operation on explicit permission this turn.
233
+ resolution: >-
234
+ Both rules apply independently and compose. The
235
+ `verify-before-complete` Iron Law still requires fresh
236
+ verification output in this message before any "done" claim,
237
+ regardless of whether the user has authorised the next git op.
238
+ Conversely, verification passing does not authorise pushing or
239
+ merging — those stay behind the `scope-control` permission gate.
240
+ Skipping either is a rule violation; satisfying one does not
241
+ satisfy the other.
242
+ evidence:
243
+ - .agent-src.uncompressed/rules/verify-before-complete.md#the-iron-law
244
+ - .agent-src.uncompressed/rules/scope-control.md#git-operations--permission-gated
245
+
224
246
  - id: language-x-direct-answers
225
247
  rules: [language-and-tone, direct-answers]
226
248
  relation: complements
@@ -53,7 +53,7 @@ those sections.
53
53
  | `personal.open_edited_files` | `false` | Open edited files in IDE |
54
54
  | `personal.ide` | *(empty)* | IDE for file opening (`cursor`, `code`, `phpstorm`) |
55
55
  | `pipelines.skill_improvement` | `true` | Post-task learning capture. Included in every profile except `custom`. |
56
- | `chat_history.enabled` | `true` | Persistent JSONL log at `.agent-chat-history` for crash recovery. |
56
+ | `chat_history.enabled` | `true` | Persistent JSONL log at `agents/.agent-chat-history` for crash recovery. |
57
57
  | `chat_history.frequency` | per profile | Logging granularity: `per_turn`, `per_phase`, or `per_tool` (see matrix below). |
58
58
  | `chat_history.max_size_kb` | per profile | Max file size before overflow handling (see matrix below). |
59
59
  | `chat_history.on_overflow` | per profile | `rotate` drops oldest, `compress` marks for summarization (see matrix below). |
@@ -66,6 +66,7 @@ those sections.
66
66
  | `ai_council.cost_budget.max_calls` | `10` | Maximum council members per invocation. |
67
67
  | `ai_council.cost_budget.max_total_usd` | `0.0` | Per-invocation USD ceiling. `0` disables (token caps still apply). |
68
68
  | `ai_council.cost_budget.daily_limit_usd` | `0.0` | Rolling 24h USD ceiling across all `/council` calls. `0` disables. Ledger lives at `~/.config/agent-config/council-spend.jsonl` (mode 0600). |
69
+ | `ai_council.session_retention_days` | `14` | Auto-prune for `agents/council-sessions/` audit folders. Older session directories are removed on the next `save()`. `0` disables (keep forever). |
69
70
 
70
71
  > **Experimental.** AI Council is not yet validated by external users. API costs apply per consultation.
71
72
 
@@ -17,7 +17,10 @@
17
17
 
18
18
  ## Task Commands
19
19
 
20
- All commands use [Task](https://taskfile.dev/). See `Taskfile.yml` for the full list.
20
+ All commands use [Task](https://taskfile.dev/). The root `Taskfile.yml` orchestrates
21
+ `ci`/`_ci-*` and includes the four task groups under `taskfiles/`
22
+ (`ci-fast.yml`, `content.yml`, `engine.yml`, `release.yml`) with `flatten: true`,
23
+ so every task stays in the root namespace. Run `task --list` for the full list.
21
24
 
22
25
  ### CI & Verification
23
26
 
@@ -115,7 +115,7 @@ Your agent is now:
115
115
  - **Respecting your codebase** — no conflicting patterns
116
116
  - **Following standards** — consistent code quality
117
117
 
118
- This is enforced automatically by 58 rules. No configuration needed.
118
+ This is enforced automatically by 56 rules. No configuration needed.
119
119
 
120
120
  ---
121
121
 
@@ -151,41 +151,33 @@ Your agent now understands slash commands:
151
151
  | `/optimize skills` | Audit skills, find duplicates, run linter |
152
152
  | `/feature plan` | Interactively plan a feature |
153
153
  | `/quality-fix` | Run and fix all quality checks |
154
- | `/chat-history` | Inspect the persistent chat-history log |
155
- | `/chat-history-resume` | Recover context after a crashed or switched session |
156
- | `/chat-history-clear` | Wipe the chat-history log (with confirmation) |
154
+ | `/chat-history` | Inspect the persistent chat-history log (read-only `show`) |
157
155
 
158
- → [Browse all 95 active commands](../.agent-src/commands/)
156
+ → [Browse all 94 active commands](../.agent-src/commands/)
159
157
 
160
158
  ---
161
159
 
162
- ## Crash recovery — `.agent-chat-history`
160
+ ## Crash recovery — `agents/.agent-chat-history`
163
161
 
164
162
  When `chat_history.enabled: true` in `.agent-settings.yml` (on by default
165
163
  for every profile), the agent keeps a JSONL log of your conversation in
166
- `.agent-chat-history` at the project root. The file is git-ignored and
167
- rotates at the size configured in the profile (`128 KB` on `minimal`,
168
- `256 KB` on `balanced`, `512 KB` on `full`).
169
-
170
- When a chat opens and finds an existing log, the host agent is
171
- instructed to run a 4-state ownership check and choose the right
172
- flow:
173
-
174
- - **match** — this chat already owns the file. Append silently.
175
- - **foreign** — a different session's file. You get 3 options:
176
- Resume (adopt), New start (archive + init), Ignore (skip logging).
177
- - **returning** this chat once owned the file, but another session
178
- took over in between. You get 3 options: Merge (your history in front
179
- of the foreign entries), Replace (wipe foreign entries, keep yours
180
- only), Continue (just leave the file and append from now on).
181
- - **missing** — no file yet. Init and proceed.
182
-
183
- Run `/chat-history-resume` to walk through the prompts explicitly, or
184
- let the agent ask on the first turn of a new chat. All merge/replace/
185
- resume paths read the on-disk entries into context before any write.
186
-
187
- See the [`chat-history` rule](../.agent-src/rules/chat-history-ownership.md) and
188
- [`scripts/chat_history.py`](../scripts/chat_history.py) for the mechanics.
164
+ `agents/.agent-chat-history`. The file is git-ignored and rotates at the
165
+ size configured in the profile (`128 KB` on `minimal`, `256 KB` on
166
+ `balanced`, `512 KB` on `full`).
167
+
168
+ Logging is **hook-only**: a structural Augment hook fires on
169
+ `session_start` and binds the log to the current session via auto-adopt
170
+ — no agent prompts, no ownership questions. The file is rewritten
171
+ transparently if the fingerprint does not match (fresh chat) and
172
+ otherwise appended to.
173
+
174
+ Run `/chat-history` (a.k.a. `/chat-history show`) any time to inspect
175
+ the log size, last entries, and current fingerprint. For the rare case
176
+ where auto-adopt misfires (corrupted file, hook misconfiguration), run
177
+ `./agent-config chat-history:adopt` as the manual recovery lever.
178
+
179
+ See [`agents/contexts/chat-history-platform-hooks.md`](../agents/contexts/chat-history-platform-hooks.md)
180
+ and [`scripts/chat_history.py`](../scripts/chat_history.py) for the mechanics.
189
181
 
190
182
  ---
191
183
 
@@ -106,7 +106,7 @@ Agent: Bevor ich die Roadmap übergebe:
106
106
  - Welcher Branch?
107
107
  - Soll ich PRs erwähnen?
108
108
  - Welches Modell für die Fortsetzung?
109
- - Soll ich .agent-chat-history zitieren?
109
+ - Soll ich agents/.agent-chat-history zitieren?
110
110
 
111
111
  Antworte als 1, 2, 3, 4.
112
112
  ```
@@ -152,27 +152,46 @@ MUST follow these rules. Initial file creation and legacy migration
152
152
  are owned by `scripts/install.py`; these rules govern every edit
153
153
  after that.
154
154
 
155
+ The contract is **additive merge with user-line preservation** —
156
+ the user's file is the ground truth, the template only contributes
157
+ keys the user is missing. Round-trip parser and merger live in
158
+ [`scripts/sync_yaml_rt.py`](../../scripts/sync_yaml_rt.py); the
159
+ supported YAML subset (block-mappings, scalars, lists, comments,
160
+ CRLF/LF) is documented in its module docstring. The stdlib-only
161
+ choice (vs. `ruamel.yaml`) and its revisit triggers are recorded in
162
+ [`docs/contracts/adr-settings-sync-engine.md`](../../contracts/adr-settings-sync-engine.md).
163
+
155
164
  For each section in the template
156
- ([`agent-settings.md`](../../templates/agent-settings.md)), walked in
157
- template order:
165
+ ([`agent-settings.md`](../../templates/agent-settings.md)):
158
166
 
159
- - Keep the section header and its comments verbatim from the template.
160
167
  - For each key under the section:
161
- - **Key exists in user's file** → use the user's current value.
162
- - **Key missing** use the template default.
163
- - **Unknown sections/keys** the user has added preserve at the end
164
- of the section (or in a trailing `_user:` block if no matching
165
- section exists).
168
+ - **Key exists in user's file** → keep the user's line **verbatim**
169
+ (value, quoting, inline comment, indent all preserved).
170
+ - **Key missing** insert the template's line at the position
171
+ after the user's last preceding sibling that is also in the
172
+ template (max-index insertion).
173
+ - **Unknown sections/keys** the user has added → preserved verbatim
174
+ at their existing position. They are not moved to a trailing
175
+ `_user:` block, not re-prefixed, not flattened.
166
176
 
167
177
  Invariants:
168
178
 
169
- - Template section **order** always wins reorder existing keys to
170
- match.
179
+ - **User order wins.** Template order is only consulted to decide
180
+ where to insert missing keys; existing user keys are never
181
+ reordered.
171
182
  - Existing scalar values are **never overwritten** unless the user
172
183
  asked for that specific change.
173
- - New keys added to the template land with their default value.
174
- - Comments from the template replace user comments in the same
175
- position comments are documentation, not user data.
184
+ - New keys added to the template land with their default value and
185
+ the template's leading comments.
186
+ - **User comments are preserved verbatim** on every existing key.
187
+ Template comments only land with keys the merger inserts; once a
188
+ key is in the user's file, its surrounding comments are owned by
189
+ the user.
190
+ - Legacy `_user._user.foo` corruption (accumulated by older buggy
191
+ syncs) heals on the next sync — the leading `_user.` chain is
192
+ stripped and the leaf is re-homed at its template path, or kept
193
+ as a single-level orphan under `_user:` if no template home
194
+ exists.
176
195
  - Write with 2-space indent, no tabs, no trailing whitespace.
177
196
  - Never commit — `.agent-settings.yml` is git-ignored.
178
197
  - If a legacy flat `.agent-settings` (key=value) is still present,