@event4u/agent-config 2.13.0 → 2.14.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 (64) hide show
  1. package/.agent-src/commands/memory/learn-low-impact.md +143 -0
  2. package/.agent-src/rules/ask-when-uncertain.md +10 -6
  3. package/.agent-src/rules/copilot-routing.md +1 -1
  4. package/.agent-src/rules/devcontainer-routing.md +1 -1
  5. package/.agent-src/rules/external-reference-deep-dive.md +1 -1
  6. package/.agent-src/rules/fast-path-marker-visibility.md +38 -0
  7. package/.agent-src/rules/low-impact-corpus-privacy-floor.md +74 -0
  8. package/.agent-src/rules/symfony-routing.md +1 -1
  9. package/.agent-src/skills/ai-council/SKILL.md +208 -8
  10. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  11. package/.claude-plugin/marketplace.json +2 -1
  12. package/CHANGELOG.md +299 -124
  13. package/README.md +6 -6
  14. package/config/gitignore-block.txt +6 -0
  15. package/docs/architecture.md +12 -12
  16. package/docs/archive/CHANGELOG-pre-2.11.0.md +141 -0
  17. package/docs/catalog.md +10 -7
  18. package/docs/contracts/adr-architectural-consensus-mechanism.md +4 -3
  19. package/docs/contracts/adr-level-6-productization.md +7 -9
  20. package/docs/contracts/ai-council-config.md +492 -20
  21. package/docs/contracts/command-clusters.md +1 -1
  22. package/docs/contracts/command-surface-tiers.md +3 -2
  23. package/docs/contracts/cost-profile-defaults.md +5 -0
  24. package/docs/contracts/decision-engine-gates.md +5 -0
  25. package/docs/contracts/decision-trace-v1.md +2 -2
  26. package/docs/contracts/file-ownership-matrix.json +1735 -72
  27. package/docs/contracts/installed-tools-lockfile.md +2 -1
  28. package/docs/contracts/low-impact-corpus-format.md +95 -0
  29. package/docs/contracts/mcp-beta-criteria.md +6 -5
  30. package/docs/contracts/mcp-cloud-scope.md +5 -4
  31. package/docs/contracts/multi-tool-projection-fidelity.md +8 -2
  32. package/docs/contracts/release-trunk-sync.md +4 -3
  33. package/docs/contracts/tier-3-contrib-plugin.md +5 -6
  34. package/docs/getting-started.md +2 -2
  35. package/docs/guidelines/agent-infra/installed-tools-manifest.md +2 -1
  36. package/docs/installation.md +32 -0
  37. package/package.json +1 -1
  38. package/scripts/_cli/cmd_doctor.py +134 -0
  39. package/scripts/ai_council/airgap.py +165 -0
  40. package/scripts/ai_council/cli_hints.py +123 -0
  41. package/scripts/ai_council/clients.py +787 -5
  42. package/scripts/ai_council/compile_corpus.py +178 -0
  43. package/scripts/ai_council/confidence_gate.py +156 -0
  44. package/scripts/ai_council/config.py +1007 -11
  45. package/scripts/ai_council/consensus.py +41 -2
  46. package/scripts/ai_council/events_log.py +137 -0
  47. package/scripts/ai_council/learn_low_impact_preview.py +252 -0
  48. package/scripts/ai_council/low_impact.py +714 -0
  49. package/scripts/ai_council/low_impact_corpus.py +466 -0
  50. package/scripts/ai_council/low_impact_intake.py +163 -0
  51. package/scripts/ai_council/modes.py +6 -1
  52. package/scripts/ai_council/necessity.py +782 -0
  53. package/scripts/ai_council/orchestrator.py +252 -14
  54. package/scripts/ai_council/probation_gate.py +152 -0
  55. package/scripts/ai_council/redact_low_impact_entry.py +155 -0
  56. package/scripts/ai_council/replay.py +155 -0
  57. package/scripts/ai_council/session.py +19 -1
  58. package/scripts/ai_council/shadow_dispatch.py +235 -0
  59. package/scripts/ai_council/solo_dispatch.py +226 -0
  60. package/scripts/audit_cloud_compatibility.py +74 -0
  61. package/scripts/audit_command_surface.py +363 -0
  62. package/scripts/check_council_layout.py +11 -0
  63. package/scripts/council_cli.py +1046 -15
  64. package/scripts/install.sh +12 -0
@@ -0,0 +1,143 @@
1
+ ---
2
+ name: memory:learn-low-impact
3
+ tier: 2
4
+ cluster: memory
5
+ sub: learn-low-impact
6
+ skills: [ai-council, upstream-contribute]
7
+ description: Preview validated low-impact entries that would be upstreamed to the package seed (default `--preview`); `--apply` opens a draft PR via `upstream-contribute` after re-redaction.
8
+ disable-model-invocation: true
9
+ suggestion:
10
+ eligible: true
11
+ trigger_description: "upstream low-impact decisions, share validated council questions, contribute the learning corpus"
12
+ trigger_context: "user has accumulated validated entries in agents/low-impact-decisions.md and wants to share with the package"
13
+ ---
14
+
15
+ # /memory learn-low-impact
16
+
17
+ Promote `## Validated` entries from
18
+ [`agents/low-impact-decisions.md`](../../agents/low-impact-decisions.md)
19
+ into the upstream seed at
20
+ `.agent-src.uncompressed/data/low-impact-decisions-seed.md` via a DRAFT
21
+ PR against the agent-config package. **Validated entries only** — probation
22
+ entries never upstream, they're unconfirmed signal.
23
+
24
+ ## Flags
25
+
26
+ | Flag | Default | Behaviour |
27
+ |---|---|---|
28
+ | `--preview` | **on** | Build the plan, run the redactor, render promoted / refused / already-seeded buckets + draft PR body. **No file write, no branch, no PR.** Default behaviour. |
29
+ | `--apply` | off | Mutually exclusive with `--preview`. Required to invoke `upstream-contribute` and open the draft PR. Refusals from the redactor still block. |
30
+
31
+ Iron Law: ``--apply`` never auto-fires on the first invocation. The
32
+ user always sees the preview block first and re-runs explicitly.
33
+
34
+ ## Iron Law — privacy floor runs TWICE
35
+
36
+ ```
37
+ THE REDACTOR RUNS AT INTAKE (WRITE GATE) AND AGAIN HERE (UPSTREAM GATE).
38
+ ANY VIOLATION → REFUSE THE PR. NO SILENT REWRITES.
39
+ ```
40
+
41
+ See [`low-impact-corpus-privacy-floor`](../rules/low-impact-corpus-privacy-floor.md)
42
+ for the eight forbidden-content classes.
43
+
44
+ ## Steps
45
+
46
+ ### 1. Build the preview plan
47
+
48
+ Call
49
+ `scripts/ai_council/learn_low_impact_preview.py::build_preview` with
50
+ the project-local corpus and the package seed:
51
+
52
+ ```python
53
+ from scripts.ai_council.learn_low_impact_preview import build_preview
54
+ plan = build_preview(
55
+ corpus_path="agents/low-impact-decisions.md",
56
+ seed_path=".agent-src.uncompressed/data/low-impact-decisions-seed.md",
57
+ repo_slug="<owner>/<repo>", # from `git remote get-url origin`
58
+ repo_root="<absolute repo root>",
59
+ private_domains=(), # from .agent-settings.yml policy
60
+ customer_names=(), # from .agent-settings.yml policy
61
+ sql_identifiers=(), # from .agent-settings.yml policy
62
+ )
63
+ ```
64
+
65
+ The builder runs all three contract checks in one pass:
66
+
67
+ 1. Parses `## Validated` (strict mode — drift surfaces as
68
+ `CorpusParseError`).
69
+ 2. Diffs against the seed file — already-seeded entries land in
70
+ `plan.already_seeded` and never upstream.
71
+ 3. Re-runs `redact_low_impact_entry` on every candidate. Failures
72
+ land in `plan.refused`.
73
+
74
+ ### 2. Surface the preview block
75
+
76
+ Print `plan.render()` verbatim. Always. This is the user-facing
77
+ audit trail per `fast-path-marker-visibility` Iron Law — the host
78
+ agent MUST NOT swallow or paraphrase it.
79
+
80
+ ```
81
+ ## learn-low-impact preview — repo=<slug>
82
+ last-upstreamed: <sha>
83
+ seed: <path>
84
+
85
+ ### Promoted (N) …
86
+ ### Refused (M) — redactor blocked …
87
+ ### Already seeded (K) …
88
+ ```
89
+
90
+ ### 3. Decide based on the flag
91
+
92
+ - **`--preview` (default)** — stop here. If `plan.would_open_pr` is
93
+ true, the rendered block ends with
94
+ `> Re-run with \`--apply\` to open the draft PR via \`upstream-contribute\`.`
95
+ Hand control back to the user.
96
+ - **`--apply`** — refuse when `plan.refused` is non-empty; surface
97
+ the refusals and stop. Otherwise invoke
98
+ [`upstream-contribute`](../skills/upstream-contribute/SKILL.md)
99
+ with:
100
+ - **target file:** `.agent-src.uncompressed/data/low-impact-decisions-seed.md`
101
+ - **PR title:** `plan.render_pr_body()` first heading
102
+ - **PR body:** `plan.render_pr_body()`
103
+ - **patch:** `plan.render_diff()`
104
+ - **draft:** `true` — never auto-merge; review is a human gate.
105
+
106
+ ### 4. Advance the local baseline (`--apply` path only)
107
+
108
+ When the PR is opened (step 3 returns a PR URL + new commit SHA on
109
+ the package branch):
110
+
111
+ ```bash
112
+ # update the local pointer so subsequent runs are deltas
113
+ sed -i.bak -E "s|^last-upstreamed: .*|last-upstreamed: <new-sha>|" \
114
+ agents/low-impact-decisions.md
115
+ rm agents/low-impact-decisions.md.bak
116
+ ```
117
+
118
+ ### 5. Surface result (`--apply` path only)
119
+
120
+ ```
121
+ > Drafted PR <url>
122
+ > Entries upstreamed: N
123
+ > Provenance bumped: <old-sha> → <new-sha>
124
+ ```
125
+
126
+ ## Halt conditions
127
+
128
+ - Redactor refuses (any class) — surface, stop. `--apply` is rejected.
129
+ - No candidates (`plan.has_work == False`) — exit 0 with the preview
130
+ block; no PR even on `--apply`.
131
+ - `--preview` (default) — always stops before any side-effect.
132
+ - Package repo unavailable per `upstream-contribute § Step 4` — surface
133
+ the access options, stop.
134
+ - User explicitly declines the PR option — exit 0, no PR.
135
+
136
+ ## See also
137
+
138
+ - [`upstream-contribute`](../skills/upstream-contribute/SKILL.md) — PR
139
+ machinery (branch, commit, gates).
140
+ - [`agents/low-impact-decisions.md`](../../agents/low-impact-decisions.md)
141
+ — the project-local corpus.
142
+ - [`low-impact-corpus-privacy-floor`](../rules/low-impact-corpus-privacy-floor.md)
143
+ — Iron Law.
@@ -8,7 +8,7 @@ source: package
8
8
 
9
9
  # Ask When Uncertain
10
10
 
11
- **When in doubt, ask.** Don't guess, assume, or improvise. One question too many beats one wrong assumption.
11
+ **When in doubt, ask.** Don't guess or improvise. One question too many beats one wrong assumption.
12
12
 
13
13
  ## Iron Law — one question per turn, ALWAYS
14
14
 
@@ -17,7 +17,7 @@ ONE QUESTION PER TURN. NO EXCEPTIONS.
17
17
  ASK. WAIT FOR THE ANSWER. THEN ASK THE NEXT.
18
18
  ```
19
19
 
20
- Even if trivial, independent, or batchable — exactly one.
20
+ Even if trivial or independent — exactly one.
21
21
 
22
22
  ## When to ask
23
23
 
@@ -49,14 +49,18 @@ Any "yes" → **collapse to ONE question**. Hold the rest for their own turn. Ra
49
49
 
50
50
  ### Ordering & handoff
51
51
 
52
- - **Session handoff** (`/agent-handoff`, fresh-chat) — ask LAST, after domain / clarifying questions, so answers fold into the handoff. Full: [`agent-interaction-and-decision-quality § handoff`](../docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md#handoff--model-switch-questions).
53
- - **Model switch** — [`model-recommendation`](model-recommendation.md) STOP-AND-WAIT gate is standalone, not appended.
54
- - **Blocking clarification** — ask FIRST, alone, before any research or planning output.
52
+ - **Session handoff** — ask LAST, after domain / clarifying questions. Full: [`agent-interaction-and-decision-quality § handoff`](../docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md#handoff--model-switch-questions).
53
+ - **Model switch** — [`model-recommendation`](model-recommendation.md) STOP-AND-WAIT gate is standalone.
54
+ - **Blocking clarification** — ask FIRST, alone, before research / planning output.
55
55
  - **Optional refinement** — don't ask; state the assumption, proceed.
56
56
 
57
+ ## Impact-based routing (AI Council)
58
+
59
+ AI Council enabled → questions classified and routed per `decision_resolution`. **Iron Law: `high_impact` and `user_required` ALWAYS reach the user.** Contract: [`ai-council-config`](../docs/contracts/ai-council-config.md#decision-resolution-by-impact-phase-10-ask-user-routing).
60
+
57
61
  ## Creating new agent artifacts
58
62
 
59
- Skill / rule / command / guideline creation or major rewrite → [`artifact-drafting-protocol`](artifact-drafting-protocol.md) (Understand → Research → Draft). Don't improvise questions.
63
+ Skill / rule / command / guideline → [`artifact-drafting-protocol`](artifact-drafting-protocol.md) (Understand → Research → Draft).
60
64
 
61
65
  ## Examples
62
66
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: "auto"
3
3
  tier: "3"
4
- description: "When configuring the GitHub Copilot AI assistant — copilot-instructions.md, PR-review comment patterns, suggestion behavior — route to the copilot-config skill"
4
+ description: "Configuring GitHub Copilot — copilot-instructions.md, PR-review comment patterns, suggestion behavior — route to the copilot-config skill"
5
5
  source: package
6
6
  triggers:
7
7
  - keyword: "copilot"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: "auto"
3
3
  tier: "3"
4
- description: "When wiring DevContainers or GitHub Codespaces — devcontainer.json, container images, VS Code features, port forwarding — route to the devcontainer skill"
4
+ description: "Wiring DevContainers or GitHub Codespaces — devcontainer.json, images, VS Code features, port forwarding — route to the devcontainer skill"
5
5
  source: package
6
6
  triggers:
7
7
  - keyword: "devcontainer"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: "auto"
3
3
  tier: "2b"
4
- description: "When the user names an external repo, file, URL, or artifact as a reference — fetch the actual tree and inspect, never summarize from README or metadata"
4
+ description: "User names an external repo, file, URL, or artifact as reference — fetch the actual tree and inspect, never summarize from README or metadata"
5
5
  alwaysApply: false
6
6
  source: package
7
7
  triggers:
@@ -0,0 +1,38 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "1"
4
+ description: "Low-impact council fast-path dispatch — host agent MUST surface the transparency marker verbatim in the reply opening; never swallow or paraphrase it."
5
+ source: package
6
+ triggers:
7
+ - keyword: "low-impact council"
8
+ - keyword: "fast-path"
9
+ - keyword: "Resolved via low-impact council"
10
+ - keyword: "low_impact"
11
+ - intent: "low-impact council dispatch"
12
+ validator_ignore:
13
+ - type: "substring"
14
+ pattern: ".agent-src.uncompressed/"
15
+ reason: "Compressor injects a back-pointer to the uncompressed source for full failure-modes detail."
16
+ ---
17
+
18
+ # Fast-Path Marker Visibility
19
+
20
+ ## The Iron Law
21
+
22
+ ```
23
+ EVERY LOW-IMPACT COUNCIL FAST-PATH REPLY OPENS WITH THE EXACT MARKER.
24
+ NEVER PARAPHRASE. NEVER SWALLOW. NEVER SUBSTITUTE THE AGENT'S OWN VERDICT.
25
+ ```
26
+
27
+ Markers (from `scripts/ai_council/low_impact.py`):
28
+
29
+ - **Resolved** — `> Resolved via low-impact council fast-path: <verdict>.`
30
+ - **Unavailable** — `> Low-impact council unavailable (no opted-in members) — escalating to user.`
31
+ - **Split** — `> Low-impact council split — escalating to user (<m1>: X / <m2>: Y):`
32
+ - **Aborted** — `> Low-impact council aborted (token cap) — escalating to user:`
33
+
34
+ Verbatim = first non-whitespace line, English (no translation), no emoji prefix, no merged numbered-options. Marker is the only audit signal that distinguishes fast-path from local deliberation. See `.agent-src.uncompressed/rules/fast-path-marker-visibility.md` for full failure modes.
35
+
36
+ Scope: `low_impact` class only. `high_impact` and `user_required` never reach fast-path.
37
+
38
+ See: [`ai-council-config § Low-impact council opt-in`](../docs/contracts/ai-council-config.md#low-impact-council-opt-in), [`direct-answers`](direct-answers.md) (invented-facts Iron Law kin).
@@ -0,0 +1,74 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "1"
4
+ description: "Writing, editing, or upstreaming entries in `agents/low-impact-decisions.md` — non-bypassable privacy floor for the learning corpus."
5
+ source: package
6
+ triggers:
7
+ - path_prefix: "agents/low-impact-decisions"
8
+ - keyword: "low-impact-decisions"
9
+ - keyword: "low-impact corpus"
10
+ - keyword: "learn-low-impact"
11
+ ---
12
+
13
+ # Low-Impact Corpus — Privacy Floor
14
+
15
+ ## Iron Law
16
+
17
+ ```
18
+ NO ENTRY LEAVES THE PROJECT REPO UNTIL THE REDACTOR CLEARS IT.
19
+ NO SECRETS. NO EMAILS. NO PROJECT PATHS. NO CUSTOMER NAMES.
20
+ NO INTERNAL HOSTNAMES. NO MONEY. NO BUSINESS SQL. NO LONG CODE.
21
+ ```
22
+
23
+ Redactor lives in `scripts/ai_council/redact_low_impact_entry.py`
24
+ and runs at **both** gates:
25
+
26
+ 1. **Write gate** — every intake append to
27
+ `agents/low-impact-decisions.md` (Phase 12 § Step 2).
28
+ 2. **Upstream gate** — every `/memory learn-low-impact` PR draft,
29
+ before diff leaves repo (Phase 12 § Step 5).
30
+
31
+ Failure at either gate refuses the operation, surfaces offending
32
+ pattern, asks user to rephrase. Redactor never auto-rewrites — silent
33
+ rewriting is soft gate, this is hard.
34
+
35
+ ## Forbidden-content classes (8)
36
+
37
+ | # | Class | Pattern source |
38
+ |---|---|---|
39
+ | 1 | Secrets | raw-key prefixes from `scripts/ai_council/config._RAW_KEY_PREFIXES` + inline `api_key:` shape |
40
+ | 2 | Emails | RFC-5322-ish |
41
+ | 3 | Project-rooted paths | `/Users/`, `/home/`, `/opt/`, `/private/`, drive letters, configured `repo_root` |
42
+ | 4 | Customer / tenant names | caller-supplied list; generic placeholders (`<customer>`, `<tenant>`, `<account>`, `<user>`) survive |
43
+ | 5 | Internal hostnames | `*.internal`, `*.local`, caller-supplied private domains |
44
+ | 6 | Monetary amounts | `$1,234`, `€500`, `USD 1000` shapes |
45
+ | 7 | Business-context SQL identifiers | caller-supplied table / column list |
46
+ | 8 | Inline code excerpts > 40 chars | backtick-fenced runs |
47
+
48
+ ## Locked target types
49
+
50
+ - `agents/low-impact-decisions.md` — project-local corpus.
51
+ - `data/low-impact-decisions-seed.md` (agent-config package) —
52
+ upstream seed shipped with the package.
53
+
54
+ ## When to invoke
55
+
56
+ - Host agent just received user intake trigger (see
57
+ `scripts/ai_council/low_impact_intake.TRIGGER_PHRASES`).
58
+ - Host agent about to write entry to corpus or open `/memory learn-low-impact` PR.
59
+
60
+ ## What to surface on refusal
61
+
62
+ One-line marker:
63
+
64
+ ```
65
+ > Low-impact corpus refused — <category>: <snippet…>. Rephrase or skip.
66
+ ```
67
+
68
+ Then agent stops intake/upstream flow. No silent retry, no auto-rewrite.
69
+
70
+ ## See also
71
+
72
+ - `scripts/ai_council/redact_low_impact_entry.py` — the redactor.
73
+ - `scripts/ai_council/low_impact_intake.py` — write-gate caller.
74
+ - `agents/low-impact-decisions.md` — corpus + Anti-Examples list.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: "auto"
3
3
  tier: "3"
4
- description: "When writing or reviewing Symfony code — DI container, bundles, Doctrine, Messenger, Security voters, console commands — route to the symfony-workflow skill"
4
+ description: "Writing or reviewing Symfony code — DI, bundles, Doctrine, Messenger, Security voters, console commands — route to the symfony-workflow skill"
5
5
  source: package
6
6
  triggers:
7
7
  - keyword: "symfony"
@@ -5,6 +5,8 @@ source: package
5
5
  domain: process
6
6
  ---
7
7
 
8
+ <!-- cloud_safe: degrade -->
9
+
8
10
  > **Experimental.** AI Council is not yet validated by external users. API costs apply per consultation.
9
11
 
10
12
  # ai-council
@@ -30,6 +32,45 @@ Do NOT use when:
30
32
  * The user has not configured any council member → state that and stop;
31
33
  do not silently fall back to anything.
32
34
 
35
+ ## When NOT to invoke — necessity self-check
36
+
37
+ Phase 6 necessity classifier (see
38
+ [`ai-council-config § Necessity classifier`](../../../docs/contracts/ai-council-config.md))
39
+ runs as pre-flight gate inside CLI, skips council when prompt looks
40
+ like routine work. Route around it BEFORE gate fires so user never pays
41
+ classifier-pause cost on request that obviously did not need council.
42
+
43
+ Skip council, stay in-session for:
44
+
45
+ * **Bugfix shape** — stack trace, error, crash, failing test, "broken",
46
+ regression. Use `systematic-debugging` or `bug-investigate`.
47
+ * **Syntax / format / lint** — `typo`, `formatting`, `lint`, `indent`,
48
+ `import order`, simple rename. Use language skill directly
49
+ (`php-coder`, `eloquent`, `nextjs-patterns`).
50
+ * **Single-file implementation** — "this function", "this method",
51
+ "this file", "one-liner", "small change", "add a getter". Use
52
+ language skill directly.
53
+ * **Documentation lookup** — "what is X", "how does Y work", "example
54
+ of Z", "syntax of W". Use `codebase-retrieval` or docs skill, never
55
+ council.
56
+
57
+ Invoke council when:
58
+
59
+ * **Architectural / structural** — system boundaries, coupling,
60
+ refactor strategy, migration plan, rewrite vs redesign.
61
+ * **Multi-axis trade-off** — stakeholders disagree; competing
62
+ alternatives need weighing; "pros and cons" is the actual ask.
63
+ * **Strategic / direction** — "should we …", "shall we …", roadmap
64
+ shape, long-term technical direction.
65
+ * **Explicit ambiguity** — user wrote "unsure / uncertain / ambiguous
66
+ / second opinion / sanity check".
67
+
68
+ Agent orchestration MUST call `council_cli` with `--invocation agent`
69
+ so gate can skip silently on routine requests. User-typed `/council`
70
+ keeps default (`--invocation user_explicit`); user gets educational
71
+ message + `--proceed-anyway` override path. Mode `block` ignores
72
+ `--proceed-anyway` by design — cost-strict opt-in.
73
+
33
74
  ## Goal
34
75
 
35
76
  Bring in **independent** external models to critique a project
@@ -89,8 +130,9 @@ travel changes.
89
130
 
90
131
  | Mode | Client | Billable | Transport | Status |
91
132
  |---|---|---|---|---|
92
- | `api` | `AnthropicClient` / `OpenAIClient` | yes | provider SDK + key from `~/.event4u/agent-config/<provider>.key` (legacy `~/.config/agent-config/<provider>.key` read as fallback) | shipped |
133
+ | `api` | `AnthropicClient` / `OpenAIClient` / `GeminiClient` / `XAIClient` / `PerplexityClient` | yes | provider SDK + key from `~/.event4u/agent-config/<provider>.key` (legacy `~/.config/agent-config/<provider>.key` read as fallback) | shipped |
93
134
  | `manual` | `ManualClient` | no | `stdout` (prompt block) + `stdin` (user pastes the web-UI reply, terminated by a line containing only `END`) | shipped (Phase 2b) |
135
+ | `cli` | `AnthropicCliClient` / `OpenAICliClient` / `GeminiCliClient` | no (subscription-authed) | local subprocess against the vendor CLI (`claude`, `codex`, `gemini`); auth delegated to the CLI's own session, no API key in this process | shipped (anthropic/openai/gemini · Phase 3) |
94
136
 
95
137
  Resolution lives in `scripts/ai_council/modes.py`:
96
138
  `resolve_mode(name, invocation_mode, member_settings, global_mode)`
@@ -118,16 +160,79 @@ thread** (no system prompt repetition). `2` records the round and
118
160
  moves to the next member. `3` returns `error="manual_aborted"` for
119
161
  that member and the orchestrator stops the fan-out.
120
162
 
163
+ ### CLI-mode UX
164
+
165
+ `mode: cli` runs the council through the vendor's local CLI
166
+ instead of the API. Auth is delegated — user logs into each CLI
167
+ once (`claude login`, `codex login`, `gemini`), orchestrator
168
+ inherits the subscription. No API key in this process.
169
+ `billable=False` → cost gate bypassed; the local
170
+ `cli_call_budget.max_calls_per_day.<provider>` quota (state at
171
+ `~/.event4u/agent-config/cli-calls.json`, daily UTC reset) is the
172
+ only per-day brake.
173
+
174
+ Three vendor CLIs wired:
175
+
176
+ - **Anthropic / Claude** — invokes `claude --print --output-format json`,
177
+ parses standard envelope (`result` + `usage` + `session_id` +
178
+ `total_cost_usd`). Token counts and reported cost survive to
179
+ `metadata` for audit.
180
+
181
+ ```yaml
182
+ members:
183
+ anthropic:
184
+ enabled: true
185
+ mode: cli
186
+ model: claude-sonnet-4-5
187
+ ```
188
+
189
+ - **OpenAI / Codex** — invokes `codex exec --json`, walks the
190
+ newline-delimited JSON event stream, pulls text from
191
+ `item.completed` and tokens from `turn.completed`. Session id
192
+ preserved.
193
+
194
+ ```yaml
195
+ members:
196
+ openai:
197
+ enabled: true
198
+ mode: cli
199
+ model: gpt-5
200
+ ```
201
+
202
+ - **Google / Gemini** — invokes `gemini --output-format json` with
203
+ prompt piped on stdin, parses `response` + `stats.models.<m>.tokens`
204
+ envelope. OAuth consent must be granted once interactively before
205
+ the CLI is usable from a non-interactive shell.
206
+
207
+ ```yaml
208
+ members:
209
+ gemini:
210
+ enabled: true
211
+ mode: cli
212
+ model: gemini-2.5-pro
213
+ ```
214
+
215
+ Auth-failure stderr from any vendor CLI surfaces as
216
+ `error="auth_expired"` with the original stderr tail in
217
+ `metadata.stderr_tail` so the user knows to re-login. Missing
218
+ binary at construction time fails fast with `CouncilDisabledError`
219
+ naming the binary and the YAML override path — never silently
220
+ substitutes.
221
+
222
+ `xai` + `perplexity` accept `mode: cli` from Phase 4 onward, but
223
+ their community CLIs DO consume the API key and DO NOT bypass
224
+ per-token billing — contract doc warns explicitly.
225
+
121
226
  ### Cost-gate bypass for non-billable members
122
227
 
123
228
  `ExternalAIClient.billable` is the contract. Clients with
124
- `billable=False` (`ManualClient`) bypass the cost gate entirely —
125
- the orchestrator skips the
126
- projection check, the `on_overrun` callback, and the USD-budget
127
- short-circuit for that member, but still records the response's
128
- token counts (from the manual-paste length heuristic or the
129
- provider's reply, when available) for observability. Mixed runs
130
- (one manual + one api) gate only the api members.
229
+ `billable=False` (`ManualClient`, `AnthropicCliClient`,
230
+ `OpenAICliClient`, `GeminiCliClient`) bypass the cost gate entirely —
231
+ orchestrator skips the projection check, the `on_overrun` callback,
232
+ and the USD-budget short-circuit for that member, but still records
233
+ the response's token counts (from the manual-paste length heuristic
234
+ or the provider's reply, when available) for observability. Mixed
235
+ runs (one cli + one api) gate only the api members.
131
236
 
132
237
  ## Degradation modes
133
238
 
@@ -266,6 +371,16 @@ matching `road-to-<topic-slug>` roadmap under `agents/roadmaps/`).
266
371
  + gpt-4o, YYYY-MM-DD) reviewed N candidate strategies; converged
267
372
  on …`).
268
373
 
374
+ ### Exempt
375
+
376
+ - `agents/audit-*/` — historical audit bundles. Canonical council
377
+ dirs are gitignored; audit bundles are tracked, cohesive narratives
378
+ that may include council artefacts as part of their evidence trail
379
+ (e.g. `audit-2026-05-14-north-star/` bundles its triggering
380
+ question, raw responses, and synthesis alongside the audit's
381
+ findings). The layout linter (`scripts/check_council_layout.py`)
382
+ skips these directories.
383
+
269
384
  `scripts/check_council_layout.py` is the mechanical check for the
270
385
  output path convention — wire it into the package's CI pipeline so
271
386
  violations break the build.
@@ -690,6 +805,87 @@ and call count are unaffected. Peer-review preserves the advisor
690
805
  label while stripping provider identity (`Response A (Contrarian)`).
691
806
  Two enabled advisors on the same member is a config error.
692
807
 
808
+ ## Decision-replay artefact (Phase 9, audit trail)
809
+
810
+ Every session that runs consensus scoring drops a `decision-replay.md`
811
+ next to `responses.json`. Pure projection of consensus + final-round
812
+ member texts — **no extra model calls, no extra spend**. Surfaces per
813
+ top finding: verdict band (Strong/Moderate/Weak), evidence-quality
814
+ (H/M/L), agree/dissent split, one key argument per member.
815
+
816
+ Two render modes — **Full** (per-member arguments attributed to
817
+ `provider:model`) and **Redacted** (verdict + evidence-quality + counts
818
+ only). Toggles: `ai_council.decision_replay.{enabled,
819
+ include_member_arguments}` global; `ai_council.lenses.<lens>.decision_replay.*`
820
+ per-lens override.
821
+
822
+ CLI — written automatically by `council run` on lenses that score
823
+ consensus. `council replay <responses.json>` re-renders from a saved
824
+ session; `--redact-member-arguments` / `--include-member-arguments`
825
+ flip the view independent of config (share redacted variant of an
826
+ already-paid run).
827
+
828
+ ## Lightweight-QA fast-path (Phase 11)
829
+
830
+ Low-impact questions from Phase 10's impact router → restricted fast-path
831
+ in place of full debate. Trade-off explicit: **1 round · ≤2 members ·
832
+ $0.05/answer · 2500 tokens**. No advisors, no peer-review, no consensus
833
+ scoring — quick answer + transparency marker, not deliberation.
834
+
835
+ ### Iron Law
836
+
837
+ `high_impact` and `user_required` **never** route to fast-path,
838
+ regardless of config. Schema validation rejects override. Fast-path
839
+ activates only when:
840
+
841
+ 1. `ai_council.enabled: true` AND
842
+ 2. `decision_resolution.low_impact.mode: council` AND
843
+ 3. ≥1 member has `participate_low_impact: true` (default `false` —
844
+ explicit opt-in per member).
845
+
846
+ Default `low_impact` route = **`agent`** — nothing reaches council
847
+ without explicit two-knob opt-in (flip class → `council` *and* mark
848
+ ≥1 member `participate_low_impact: true`). Worked YAML, validation,
849
+ unavailable-marker contract → [`ai-council-config § Low-impact council opt-in`](../../../docs/contracts/ai-council-config.md#low-impact-council-opt-in).
850
+
851
+ ### Output marker (always surfaced)
852
+
853
+ * **Resolved** — `> Resolved via low-impact council (anthropic): <answer>`
854
+ * **Split** — `> Low-impact council split — escalating to user (anthropic: X / openai: Y):`
855
+ * **Aborted** — `> Low-impact council aborted (token cap) — escalating to user:`
856
+
857
+ Marker mandatory — agent never silently substitutes fast-path verdict
858
+ for its own answer.
859
+
860
+ ### Session artefact
861
+
862
+ Every fast-path attempt appends one line to
863
+ `agents/council-sessions/<date>-<slug>/low-impact-resolutions.md`:
864
+
865
+ ```
866
+ 2025-05-14T10:00:00Z | resolved | members=2/2 | members(anthropic, openai) cost=$0.0034 | Q=Service vs Repository for this read path?
867
+ ```
868
+
869
+ Append-only, one line per resolution. Parser tolerates free-form
870
+ headers around canonical lines.
871
+
872
+ ### `council replay --low-impact-stats`
873
+
874
+ Re-projection of session log → summary block:
875
+
876
+ ```
877
+ $ council replay agents/council-sessions/2025-05-14-foo/responses.json --low-impact-stats
878
+ # Low-impact fast-path · session summary
879
+
880
+ - attempts: 4
881
+ - status: aborted=1 · resolved=2 · split=1
882
+ - members: anthropic=4 · openai=3
883
+ - total cost: $0.0096
884
+ ```
885
+
886
+ No model calls — pure markdown parse. Returns 0 when session has no
887
+ fast-path entries (clean session is not an error).
888
+
693
889
  ## See also
694
890
 
695
891
  - `/council` command — the user-facing entry point.
@@ -704,3 +900,7 @@ Two enabled advisors on the same member is a config error.
704
900
  - `docs/customization.md` § `ai_council.*` — settings reference.
705
901
  - `docs/contracts/ai-council-config.md` § advisors — schema + precedence
706
902
  contract.
903
+ - `docs/contracts/ai-council-config.md` § Decision-replay artefact —
904
+ Phase 9 audit trail contract + redaction modes.
905
+ - `scripts/ai_council/replay.py` — pure projection renderer (no model
906
+ calls).
@@ -39,7 +39,7 @@ schema_version: 1
39
39
  # CI guard: a release bump of `package.json` must update this value
40
40
  # in lockstep — see scripts/check_template_pin_drift.py (road-to-
41
41
  # portable-runtime-and-update-check P3.3).
42
- agent_config_version: "2.12.0"
42
+ agent_config_version: "2.13.0"
43
43
 
44
44
  # --- Project identity ---
45
45
  project:
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Shared agent configuration \u2014 skills for AI coding tools (Claude Code, Augment, Cursor, Cline, Windsurf, Gemini CLI).",
9
- "version": "2.13.0",
9
+ "version": "2.14.0",
10
10
  "keywords": [
11
11
  "agent-config",
12
12
  "skills",
@@ -208,6 +208,7 @@
208
208
  "./.claude/skills/memory",
209
209
  "./.claude/skills/memory-add",
210
210
  "./.claude/skills/memory-consolidation",
211
+ "./.claude/skills/memory-learn-low-impact",
211
212
  "./.claude/skills/memory-load",
212
213
  "./.claude/skills/memory-mine-session",
213
214
  "./.claude/skills/memory-promote",