@event4u/agent-config 2.12.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 (107) hide show
  1. package/.agent-src/commands/council/analysis.md +142 -0
  2. package/.agent-src/commands/council/debate.md +129 -0
  3. package/.agent-src/commands/council/default.md +8 -0
  4. package/.agent-src/commands/council/design.md +16 -12
  5. package/.agent-src/commands/council/optimize.md +16 -15
  6. package/.agent-src/commands/council/pr.md +12 -12
  7. package/.agent-src/commands/council.md +48 -2
  8. package/.agent-src/commands/memory/learn-low-impact.md +143 -0
  9. package/.agent-src/personas/advisors/contrarian.md +95 -0
  10. package/.agent-src/personas/advisors/executor.md +99 -0
  11. package/.agent-src/personas/advisors/expansionist.md +98 -0
  12. package/.agent-src/personas/advisors/first-principles.md +98 -0
  13. package/.agent-src/personas/advisors/outsider.md +102 -0
  14. package/.agent-src/rules/ask-when-uncertain.md +10 -6
  15. package/.agent-src/rules/copilot-routing.md +19 -0
  16. package/.agent-src/rules/devcontainer-routing.md +20 -0
  17. package/.agent-src/rules/external-reference-deep-dive.md +1 -1
  18. package/.agent-src/rules/fast-path-marker-visibility.md +38 -0
  19. package/.agent-src/rules/laravel-routing.md +20 -0
  20. package/.agent-src/rules/low-impact-corpus-privacy-floor.md +74 -0
  21. package/.agent-src/rules/symfony-routing.md +20 -0
  22. package/.agent-src/skills/ai-council/SKILL.md +388 -10
  23. package/.agent-src/skills/copilot-config/SKILL.md +1 -1
  24. package/.agent-src/skills/devcontainer/SKILL.md +1 -1
  25. package/.agent-src/skills/laravel/SKILL.md +1 -1
  26. package/.agent-src/skills/project-analysis-core/SKILL.md +1 -1
  27. package/.agent-src/skills/project-analyzer/SKILL.md +1 -1
  28. package/.agent-src/skills/symfony-workflow/SKILL.md +1 -1
  29. package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  30. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  31. package/.claude-plugin/marketplace.json +4 -1
  32. package/AGENTS.md +1 -1
  33. package/CHANGELOG.md +346 -124
  34. package/CONTRIBUTING.md +5 -0
  35. package/README.md +6 -6
  36. package/config/agent-settings.template.yml +5 -93
  37. package/config/gitignore-block.txt +6 -0
  38. package/docs/architecture/multi-tool-projection.md +53 -0
  39. package/docs/architecture/{compression.md → source-projection.md} +21 -3
  40. package/docs/architecture.md +15 -15
  41. package/docs/archive/CHANGELOG-pre-2.11.0.md +141 -0
  42. package/docs/catalog.md +25 -12
  43. package/docs/contracts/adr-architectural-consensus-mechanism.md +68 -0
  44. package/docs/contracts/adr-level-6-productization.md +7 -9
  45. package/docs/contracts/ai-council-config.md +658 -0
  46. package/docs/contracts/command-clusters.md +58 -2
  47. package/docs/contracts/command-surface-tiers.md +3 -2
  48. package/docs/contracts/cost-profile-defaults.md +5 -0
  49. package/docs/contracts/decision-engine-gates.md +5 -0
  50. package/docs/contracts/decision-trace-v1.md +2 -2
  51. package/docs/contracts/file-ownership-matrix.json +1735 -72
  52. package/docs/contracts/installed-tools-lockfile.md +2 -1
  53. package/docs/contracts/low-impact-corpus-format.md +95 -0
  54. package/docs/contracts/mcp-beta-criteria.md +6 -5
  55. package/docs/contracts/mcp-cloud-scope.md +5 -4
  56. package/docs/contracts/multi-tool-projection-fidelity.md +115 -0
  57. package/docs/contracts/release-trunk-sync.md +4 -3
  58. package/docs/contracts/tier-3-contrib-plugin.md +5 -6
  59. package/docs/getting-started.md +2 -2
  60. package/docs/guidelines/agent-infra/installed-tools-manifest.md +2 -1
  61. package/docs/installation.md +32 -0
  62. package/package.json +1 -1
  63. package/scripts/_archive/README.md +59 -0
  64. package/scripts/_cli/cmd_doctor.py +134 -0
  65. package/scripts/ai_council/_default_prices.py +10 -1
  66. package/scripts/ai_council/advisors.py +148 -0
  67. package/scripts/ai_council/airgap.py +165 -0
  68. package/scripts/ai_council/cli_hints.py +123 -0
  69. package/scripts/ai_council/clients.py +959 -5
  70. package/scripts/ai_council/compile_corpus.py +178 -0
  71. package/scripts/ai_council/confidence_gate.py +156 -0
  72. package/scripts/ai_council/config.py +1364 -0
  73. package/scripts/ai_council/consensus.py +329 -0
  74. package/scripts/ai_council/events_log.py +137 -0
  75. package/scripts/ai_council/learn_low_impact_preview.py +252 -0
  76. package/scripts/ai_council/low_impact.py +714 -0
  77. package/scripts/ai_council/low_impact_corpus.py +466 -0
  78. package/scripts/ai_council/low_impact_intake.py +163 -0
  79. package/scripts/ai_council/modes.py +6 -1
  80. package/scripts/ai_council/necessity.py +782 -0
  81. package/scripts/ai_council/orchestrator.py +872 -20
  82. package/scripts/ai_council/probation_gate.py +152 -0
  83. package/scripts/ai_council/prompts.py +335 -0
  84. package/scripts/ai_council/redact_low_impact_entry.py +155 -0
  85. package/scripts/ai_council/replay.py +155 -0
  86. package/scripts/ai_council/session.py +19 -1
  87. package/scripts/ai_council/shadow_dispatch.py +235 -0
  88. package/scripts/ai_council/solo_dispatch.py +226 -0
  89. package/scripts/audit_cloud_compatibility.py +74 -0
  90. package/scripts/audit_command_surface.py +363 -0
  91. package/scripts/check_compressed_paths.py +6 -1
  92. package/scripts/check_council_layout.py +11 -0
  93. package/scripts/ci_time_ratio.py +168 -0
  94. package/scripts/council_cli.py +2005 -30
  95. package/scripts/install.sh +12 -0
  96. package/scripts/measure_projection_bytes.py +159 -0
  97. package/scripts/measure_roadmap_trajectory.py +112 -0
  98. package/scripts/probe_projection_fidelity.py +202 -0
  99. package/scripts/score_skill_selection.py +198 -0
  100. package/scripts/skill_collision_clusters.py +162 -0
  101. /package/scripts/{_backfill_skill_domains.py → _archive/_backfill_skill_domains.py} +0 -0
  102. /package/scripts/{_bootstrap_tier_frontmatter.py → _archive/_bootstrap_tier_frontmatter.py} +0 -0
  103. /package/scripts/{_p43_bodies.py → _archive/_p43_bodies.py} +0 -0
  104. /package/scripts/{_p43_compress.py → _archive/_p43_compress.py} +0 -0
  105. /package/scripts/{_p4_migrate.py → _archive/_p4_migrate.py} +0 -0
  106. /package/scripts/{_phase2_shim_helper.py → _archive/_phase2_shim_helper.py} +0 -0
  107. /package/scripts/{_pilot_council_question.py → _archive/_pilot_council_question.py} +0 -0
@@ -0,0 +1,19 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "3"
4
+ description: "Configuring GitHub Copilot — copilot-instructions.md, PR-review comment patterns, suggestion behavior — route to the copilot-config skill"
5
+ source: package
6
+ triggers:
7
+ - keyword: "copilot"
8
+ - phrase: "copilot-instructions"
9
+ - phrase: "copilot pr review"
10
+ routes_to:
11
+ - "skill:copilot-config"
12
+ ---
13
+
14
+ # Copilot Routing
15
+
16
+ **Iron Law.** Tuning the GitHub Copilot AI assistant itself (instructions, PR-review patterns, suggestion behavior) → load the `copilot-config` skill, not `devcontainer` (which covers the dev environment Copilot runs inside).
17
+
18
+ Body migrated to `skill:copilot-config`. Disambiguates the copilot-config ↔ devcontainer cluster head per [`adr-architectural-consensus-mechanism`](../docs/contracts/adr-architectural-consensus-mechanism.md).
19
+ Trigger-set above activates this routing under the `balanced` and `full` profiles.
@@ -0,0 +1,20 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "3"
4
+ description: "Wiring DevContainers or GitHub Codespaces — devcontainer.json, images, VS Code features, port forwarding — route to the devcontainer skill"
5
+ source: package
6
+ triggers:
7
+ - keyword: "devcontainer"
8
+ - keyword: "codespaces"
9
+ - keyword: "codespace"
10
+ - phrase: "devcontainer.json"
11
+ routes_to:
12
+ - "skill:devcontainer"
13
+ ---
14
+
15
+ # Devcontainer Routing
16
+
17
+ **Iron Law.** Wiring the dev environment itself (DevContainers, Codespaces, `devcontainer.json`, VS Code features) → load the `devcontainer` skill, not `copilot-config` (which tunes the Copilot AI on top).
18
+
19
+ Body migrated to `skill:devcontainer`. Disambiguates the devcontainer ↔ copilot-config cluster head per [`adr-architectural-consensus-mechanism`](../docs/contracts/adr-architectural-consensus-mechanism.md).
20
+ Trigger-set above activates this routing under the `balanced` and `full` profiles.
@@ -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,20 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "3"
4
+ description: "When writing or reviewing Laravel code — controllers, Eloquent, Artisan, jobs, events, policies — route to the laravel skill"
5
+ source: package
6
+ triggers:
7
+ - keyword: "laravel"
8
+ - keyword: "artisan"
9
+ - keyword: "eloquent"
10
+ - keyword: "FormRequest"
11
+ routes_to:
12
+ - "skill:laravel"
13
+ ---
14
+
15
+ # Laravel Routing
16
+
17
+ **Iron Law.** Laravel-flavoured PHP (Eloquent, Artisan, FormRequest, jobs, events, policies) → load the `laravel` skill, not `symfony-workflow` and not `php-coder`.
18
+
19
+ Body migrated to `skill:laravel`. Disambiguates the laravel ↔ symfony-workflow cluster head per [`adr-architectural-consensus-mechanism`](../docs/contracts/adr-architectural-consensus-mechanism.md).
20
+ Trigger-set above activates this routing under the `balanced` and `full` profiles.
@@ -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.
@@ -0,0 +1,20 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "3"
4
+ description: "Writing or reviewing Symfony code — DI, bundles, Doctrine, Messenger, Security voters, console commands — route to the symfony-workflow skill"
5
+ source: package
6
+ triggers:
7
+ - keyword: "symfony"
8
+ - keyword: "doctrine"
9
+ - keyword: "twig"
10
+ - keyword: "messenger"
11
+ routes_to:
12
+ - "skill:symfony-workflow"
13
+ ---
14
+
15
+ # Symfony Routing
16
+
17
+ **Iron Law.** Symfony-flavoured PHP (DI container, bundles, Doctrine entities, Messenger, Security voters, console commands) → load the `symfony-workflow` skill, not `laravel` and not `php-coder`.
18
+
19
+ Body migrated to `skill:symfony-workflow`. Disambiguates the laravel ↔ symfony-workflow cluster head per [`adr-architectural-consensus-mechanism`](../docs/contracts/adr-architectural-consensus-mechanism.md).
20
+ Trigger-set above activates this routing under the `balanced` and `full` profiles.
@@ -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.
@@ -292,6 +407,65 @@ NEVER ships the host verdict as council output. Provider attribution
292
407
  stays visible in the per-member sections; host verdicts stay
293
408
  attributed to the host.
294
409
 
410
+ ## Synthesis templates (lens-aware)
411
+
412
+ The **Convergence / Divergence** slot in `council:render` output is
413
+ populated with a lens-specific synthesis prompt. The host agent reads
414
+ this prompt and writes the summary in the shape it dictates. The five
415
+ templates live in `scripts/ai_council/prompts.py::_SYNTHESIS_TABLE`
416
+ and are exposed via `synthesis_template(mode)`.
417
+
418
+ **R4 Q4 split** — decision lenses get a structured Karpathy-style
419
+ template; creative lenses stay open-ended prose (bare slot):
420
+
421
+ | Lens | Class | Synthesis sections |
422
+ |---|---|---|
423
+ | `default` | decision | Agreement · Clashes · Blind spots · Recommendation · Next step |
424
+ | `pr` | decision | Consensus · Conflicts · Must-fix before merge · Recommendation |
425
+ | `analysis` | decision | Top-10 by consensus · Supporting · Outliers |
426
+ | `design` | creative | *(no template — open prose passthrough)* |
427
+ | `optimize` | creative | *(no template — open prose passthrough)* |
428
+
429
+ Input modes (`prompt` / `roadmap` / `diff` / `files`) inherit the
430
+ `default` decision template — they are bundling shapes, not lenses.
431
+
432
+ **Source citations:**
433
+ * Template shape — Round 2 council verdict
434
+ (`agents/council-sessions/2026-05-14-ai-council-redesign/round-1.md`,
435
+ Opus's lens-adaptive synthesis proposal).
436
+ * Decision/creative split — Round 4 Q4 verdict
437
+ (`agents/council-sessions/2026-05-14-ai-council-redesign/round-3-responses.json`).
438
+ R4 reframed `optimize` as creative because perf trade-offs resist
439
+ pre-templated shape — Performance-wins / Trade-offs /
440
+ Implementation-order is too rigid for the variety of optimize-lens
441
+ artefacts. R4 reframed `design` for the same reason — design
442
+ critiques are inherently narrative.
443
+
444
+ ### `--prose-synthesis` escape hatch (R4 Q4)
445
+
446
+ Both `council:run` and `council:render` accept symmetric escape-hatch
447
+ flags on top of the lens table:
448
+
449
+ * `--prose-synthesis` — force creative-lens passthrough (bare slot)
450
+ regardless of lens. Use when the user on `default`/`pr`/`analysis`
451
+ prefers a narrative recommendation over the structured template.
452
+ * `--no-prose-synthesis` — force the `default` structured template
453
+ even on a creative lens. Use when a `design` or `optimize` artefact
454
+ has a one-shot need for Karpathy-style structure.
455
+
456
+ The flag is mutually exclusive — picking one disables the other on
457
+ the same invocation. When `council:run` records either flag in the
458
+ output JSON, `council:render` honours it unless the renderer is
459
+ called with an explicit flag of its own.
460
+
461
+ ### Renderer lens resolution
462
+
463
+ `council:render <responses.json>` resolves the active lens in this
464
+ order: explicit `--prompt-mode` flag > `prompt_mode` field in the
465
+ payload > `mode` field in the payload > `None` (default decision
466
+ template). The `--prose-synthesis` / `--no-prose-synthesis` flag
467
+ overrides the table regardless of how the lens resolved.
468
+
295
469
  ## Do NOT
296
470
 
297
471
  - Do NOT paraphrase council output into the host agent's voice — strip
@@ -435,8 +609,8 @@ prompt as `<original artefact> + <prior round, anonymised>` so each
435
609
  member can refine, agree, or push back on the previous critique
436
610
  without seeing which provider produced which point.
437
611
 
438
- The default round count comes from `ai_council.min_rounds` in
439
- `.agent-settings.yml` (default `2` so members critique each other
612
+ The default round count comes from `defaults.min_rounds` in
613
+ `agents/.ai-council.yml` (default `2` so members critique each other
440
614
  at least once before convergence). The host agent does **not** ask
441
615
  "how many rounds?" when the requested count is `<= min_rounds` —
442
616
  the settings owner already made that decision. Ask only when a
@@ -516,6 +690,202 @@ internal "more feedback" follow-up loop (1 / 2 / 3 menu) is
516
690
  **inside** a single member's chat thread and is orthogonal to the
517
691
  orchestrator-level rounds.
518
692
 
693
+ ### `/council debate` sub-command (progressive disclosure)
694
+
695
+ `/council debate <artefact> [--rounds N] [--continue-as-debate <session>]`
696
+ runs an **interactive** multi-round critique with a confirmation gate
697
+ between every round so the user can stop the spend at any point.
698
+
699
+ | Property | Behaviour |
700
+ |---|---|
701
+ | Round flow | Same orchestrator as `rounds:N` (`run_debate()`), but each round prints its responses then pauses on a y/n prompt before launching the next round. |
702
+ | Cost gate | After every round the CLI prints `Spent so far: $X · Next round: ~$Y · Cap: $Z`. `n` exits cleanly with partial results; `y` continues. |
703
+ | Hard cap | If the projected next-round cost would breach `max_total_usd`, `run_debate()` raises `DebateCapExceeded` and the CLI exits with the partial transcript. No silent overrun. |
704
+ | `--continue-as-debate` | Seeds round 1 from an existing `/council default` (or analysis lens) session. No round-1 API calls are billed; round 2+ run normally. Member list must match. |
705
+ | Session files | One file per round under `agents/council-sessions/<slug>/debate-round-NN.md`. |
706
+ | Anonymisation | Identical to `rounds:N`. The continue-as-debate path also anonymises the seeded round-1 responses when building the round-2 prompt. |
707
+
708
+ Use this when the artefact is genuinely contentious and the user
709
+ wants to control depth interactively. For a fire-and-forget
710
+ multi-round run, prefer `consult(..., rounds=N)` or `--rounds N` on
711
+ `/council default`.
712
+
713
+
714
+ ## Karpathy peer-review (opt-in)
715
+
716
+ After the final deliberation round, an optional **anonymous peer-review
717
+ pass** lets each member critique the *other* members' responses for
718
+ blind spots before synthesis. Inspired by Andrej Karpathy's "ask the
719
+ strongest models to review each other anonymously" pattern; see his
720
+ [talks / threads on inter-model critique](https://karpathy.ai/) and the
721
+ internal verdict in
722
+ `agents/council-sessions/2026-05-14-ai-council-redesign/round-2.md`
723
+ (R2 split: one approve-as-flag, one reject-as-default → opt-in only).
724
+
725
+ Pipeline order when every feature is active:
726
+
727
+ ```
728
+ deliberation rounds → peer-review → consensus-scoring → synthesis
729
+ ```
730
+
731
+ Activation — two equivalent paths:
732
+
733
+ * CLI: `--peer-review` on `council:estimate` or `council:run`.
734
+ * Config: `ai_council.peer_review.enabled: true` in
735
+ `agents/.ai-council.yml`. Default is `false`.
736
+
737
+ Mechanics:
738
+
739
+ 1. The final deliberation round's outputs are anonymised into
740
+ `Response-A`, `Response-B`, … in stable input order. Provider /
741
+ model identity is stripped (Iron-Law neutrality holds); empty or
742
+ errored deliberation responses are skipped.
743
+ 2. Each member receives an N−1 view (its own response filtered out)
744
+ plus the Karpathy prompt: *strongest response*, *weakest blind
745
+ spot*, *what did everyone miss*, *refinement*.
746
+ 3. The N critiques flow back into synthesis through a
747
+ "Peer-Review-Surfaced Blind Spots" addendum on the lens template.
748
+ 4. **Advisor preserve-persona (R4 Q3, hard-coded):** when the
749
+ deliberation was an advisor-mode run (Phase 6), anonymisation
750
+ strips provider identity but **preserves the advisor persona
751
+ label**. Peer-review renders as `Response A (Contrarian)`, never
752
+ `Response A (Anthropic Opus)`. Plain-member runs strip identity
753
+ entirely.
754
+
755
+ Cost — adds exactly N billable calls (one per member) at the same
756
+ per-call cost as a deliberation call. The `council:estimate` table
757
+ surfaces the delta as a `+peer-review: +N calls (~+$X)` row.
758
+
759
+ Needs ≥ 2 distinct deliberation outputs; below that the round is a
760
+ no-op and nothing extra is billed. Self-review is structurally
761
+ impossible — a member never sees its own response.
762
+
763
+ ## Thinking-style advisors (replace-mode)
764
+
765
+ Phase 6 introduces five **advisor personas** the council adopts in
766
+ *replace-mode*: an enabled advisor substitutes its bound member's
767
+ plain call with the same provider running the advisor's persona
768
+ prompt. Total call count stays the same — only the system prompt
769
+ swaps.
770
+
771
+ | Advisor | Default bound member | Focus |
772
+ |---|---|---|
773
+ | **Contrarian** | `anthropic` | strongest counterargument, hidden assumptions |
774
+ | **First-Principles** | `anthropic` | strip metaphor, derive from physics / math / cost |
775
+ | **Expansionist** | `openai` | adjacent opportunities, second-order effects |
776
+ | **Outsider** | `openai` | naive-but-sharp questions, beginner's-mind probes |
777
+ | **Executor** | `anthropic` | what ships this quarter, what blocks delivery |
778
+
779
+ Activation — edit `agents/.ai-council.yml` and flip the advisor's
780
+ `enabled: true`. Optional `model: <name>` overrides the bound
781
+ member's default model. An advisor referencing a disabled member
782
+ fails closed at config load — never silently skipped.
783
+
784
+ ```yaml
785
+ advisors:
786
+ contrarian:
787
+ enabled: true # ← swap anthropic's plain call for contrarian
788
+ member: anthropic
789
+ # model: claude-opus-4 # optional pin
790
+ ```
791
+
792
+ `council:estimate` surfaces every active swap on a dedicated line
793
+ above the cost table:
794
+
795
+ ```
796
+ council:estimate · mode=prompt · members=2 (billable=2)
797
+ advisor: Contrarian on anthropic via claude-sonnet-4-5
798
+ anthropic/claude-sonnet-4-5: ~991 in + 256 out = $0.0068
799
+ openai/gpt-4o: ~208 in + 256 out = $0.0031
800
+ ```
801
+
802
+ Cost-bounded — replace-mode never adds calls. The persona prompt is
803
+ larger than plain (~1k extra input tokens per swap); output tokens
804
+ and call count are unaffected. Peer-review preserves the advisor
805
+ label while stripping provider identity (`Response A (Contrarian)`).
806
+ Two enabled advisors on the same member is a config error.
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
+
519
889
  ## See also
520
890
 
521
891
  - `/council` command — the user-facing entry point.
@@ -523,6 +893,14 @@ orchestrator-level rounds.
523
893
  network, no spend, but no diversity of weights either).
524
894
  - `scripts/ai_council/prompts.py` — neutrality preamble + per-mode
525
895
  system prompts.
896
+ - `scripts/ai_council/advisors.py` — replace-mode planning + persona
897
+ resolution.
526
898
  - `scripts/ai_council/bundler.py` — redaction pattern set + size
527
899
  guard.
528
900
  - `docs/customization.md` § `ai_council.*` — settings reference.
901
+ - `docs/contracts/ai-council-config.md` § advisors — schema + precedence
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).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: copilot-config
3
- description: "Use when configuring GitHub Copilot — copilot-instructions.md, PR review patterns, output optimization even when the user just says 'tune Copilot' or 'why is Copilot commenting on X'."
3
+ description: "Tune the GitHub Copilot AI `copilot-instructions.md`, PR-review patterns, suggestion behavior, output verbosity. NOT for dev-environment setup (use `devcontainer`)."
4
4
  source: package
5
5
  domain: process
6
6
  ---