ai-consultants 2.19.2 → 2.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.
@@ -13,6 +13,7 @@ All skill details (consultants, personas, presets, strategies, features, configu
13
13
  |---------|-------------|
14
14
  | `/ai-consultants:consult` | Main consultation — ask AI consultants a coding question |
15
15
  | `/ai-consultants:debate` | Run consultation with multi-round debate |
16
+ | `/ai-consultants:roster-audit` | Audit which consultants add distinct value vs echo the panel |
16
17
  | `/ai-consultants:help` | Show this help |
17
18
 
18
19
  ## Quick Examples
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Audit the consultant roster for uncorrelated value — which consultants contribute a distinct approach vs echo the panel (candidates to drop or down-weight). Use when deciding roster composition or after noticing redundant consultations.
3
+ argument-hint: [--recent N] [--threshold PCT] [dir ...]
4
+ allowed-tools: Bash
5
+ ---
6
+
7
+ # AI Consultants - Roster Audit
8
+
9
+ Measure each consultant's *uncorrelated value* across past consultations: a
10
+ consultant whose approach rarely differs from the rest (low keyword overlap) is
11
+ redundant; one that is often distinct earns its seat on diversity. This is the
12
+ "does it add signal the others miss?" bar, applied to the panel.
13
+
14
+ **Arguments:** $ARGUMENTS
15
+
16
+ ## Instructions
17
+
18
+ 1. Run the audit (pass `$ARGUMENTS` through; with no args it audits the most
19
+ recent consultations under the output base):
20
+ ```bash
21
+ cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && ./scripts/roster_audit.sh $ARGUMENTS
22
+ ```
23
+ - No args → the 20 most recent consultation dirs.
24
+ - `--recent N` → the N most recent; `--threshold PCT` → correlation cutoff (default 20%).
25
+ - Or pass explicit consultation output dirs; add `--json` for machine-readable output.
26
+
27
+ 2. **Present the table** as-is (consultant · participated · distinct · distinct% ·
28
+ verdict), then interpret each verdict:
29
+ - **unique-value** — pulls its weight on diversity; keep.
30
+ - **some-value** — contributes occasionally.
31
+ - **redundant?** — correlated with the panel; candidate to drop or down-weight
32
+ in `references/affinity.json` (lower its category affinities, or its
33
+ capability axes when capability routing is enabled).
34
+ - **insufficient-data** — too few samples; audit more consultations.
35
+
36
+ 3. If the audit prints "nothing to audit" (exit 1), tell the user no consultations
37
+ with ≥2 responders were found and suggest running some consultations first —
38
+ each `consult_all.sh` run writes an output directory the audit can read.
package/CLAUDE.md CHANGED
@@ -6,7 +6,7 @@ AI Consultants is a multi-model AI deliberation system that queries up to 15 AI
6
6
 
7
7
  **Self-Exclusion**: The invoking agent is automatically excluded from the panel to prevent self-consultation. Claude Code won't query Claude, Codex CLI won't query Codex, etc.
8
8
 
9
- **Version**: 2.19.2
9
+ **Version**: 2.20.0
10
10
 
11
11
  ## Distribution
12
12
 
@@ -39,6 +39,10 @@ ai-consultants/
39
39
  │ ├── config.sh # Centralized configuration
40
40
  │ ├── doctor.sh # Diagnostic and auto-fix tool (v2.2)
41
41
  │ ├── peer_review.sh # Anonymous peer review (v2.2)
42
+ │ ├── roster_audit.sh # Roster uncorrelated-value audit (v2.20)
43
+ │ ├── roster_calibrate.sh # Measured capability calibration, Tier A (v2.20)
44
+ │ ├── run_calibration.sh # Calibration data-collection harness (v2.20)
45
+ │ ├── taste_elo.sh # Pairwise-judge taste Elo, Tier B (v2.20)
42
46
  │ ├── install.sh # One-liner installer (v2.2)
43
47
  │ ├── query_*.sh # Wrapper for each consultant
44
48
  │ ├── query_claude.sh # Claude consultant (v2.2)
@@ -668,6 +672,10 @@ for f in scripts/*.sh scripts/lib/*.sh; do bash -n "$f" && echo "OK: $f"; done
668
672
  | `ENABLE_COST_AWARE_ROUTING` | false | Cost-based model routing (v2.3) |
669
673
  | `ENABLE_DEBATE_OPTIMIZATION` | false | Skip debate if all agree (v2.3, opt-in) |
670
674
  | `ENABLE_COMPACT_REPORT` | true | Compact report format (v2.3) |
675
+ | `ENABLE_CAPABILITY_WEIGHTING` | false | Capability-weighted voting (v2.20, opt-in) |
676
+ | `ENABLE_CAPABILITY_ROUTING` | false | Capability-aware panel composition (v2.20, opt-in) |
677
+ | `CAPABILITY_WEIGHT_STRENGTH` | 10 | Vote-weight modulation: conf*(S+cap)/S (v2.20) |
678
+ | `CAPABILITY_DEFAULT` | 5 | Fallback capability for a missing consultant/axis (v2.20) |
671
679
  | `ENABLE_BUDGET_LIMIT` | false | Budget enforcement (v2.4, opt-in) |
672
680
  | `BUDGET_ACTION` | warn | Action on budget exceeded: warn/stop (v2.4) |
673
681
  | `QWEN3_USE_API` | false | Use DashScope API instead of qwen CLI (v2.7) |
@@ -826,6 +834,17 @@ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/s
826
834
 
827
835
  ## Changelog
828
836
 
837
+ ### v2.20.0
838
+ - **Capability axes (borrowed from the delegation-kit cost/intelligence/taste table).** `references/affinity.json` → v1.1: new `capabilities` (per-consultant {intelligence, taste, cost}, 1-10), `category_axis` (category → the quality axis it stresses: taste for API_DESIGN/ARCHITECTURE/CODE_REVIEW/GENERAL, intelligence otherwise), `capability_default`. New `lib/routing.sh::get_capability` / `get_category_axis` (cached like `get_affinity`).
839
+ - **Capability-weighted voting** (`ENABLE_CAPABILITY_WEIGHTING`, opt-in): `lib/voting.sh::_effective_vote_weight` modulates a vote by the consultant's capability on the run's axis — `confidence × (S + cap) / S` (`S = CAPABILITY_WEIGHT_STRENGTH`, default 10). Applied in `calculate_weighted_recommendation` and `calculate_final_score` (normalizer uses the same weight → 1-10 scale preserved). Axis from `QUESTION_CATEGORY`. `cost` never weights a vote (tie-break intelligence > taste > cost).
840
+ - **Capability-aware composition** (`ENABLE_CAPABILITY_ROUTING`, opt-in): `select_consultants` keeps the raw-affinity eligibility filter but ranks eligible consultants by `affinity + (cap − capability_default)`, so under a size limit the quality axis reorders who makes the cut.
841
+ - **Roster audit** — `scripts/roster_audit.sh` scores each consultant's "distinct approach" rate (max pairwise Jaccard of approaches < threshold) across consultations; verdicts unique-value / some-value / redundant? / insufficient-data. Wired as `doctor.sh --roster-audit` (short-circuit mode) and the `/ai-consultants:roster-audit` slash command (3 hosts). Reuses `voting.sh` keyword/Jaccard helpers.
842
+ - **Measured calibration** — `scripts/roster_calibrate.sh` (Tier A): intelligence/taste = mean blind peer-review score sliced by `category_axis`, cost = mean observed `tokens_used`×rate (60/40 split, rank-normalized cheapest=10); emits a `capabilities` block (`--json`/`--write`). `scripts/taste_elo.sh` (Tier B): taste via pairwise-judge Elo (pluggable judge — `JUDGE_CLI` / `TASTE_JUDGE_CMD`). `scripts/run_calibration.sh` drives `references/calibration_benchmark.json` (50 questions, 20 taste / 30 intelligence) through the panel with peer review, then calibrates.
843
+ - **Config** (`config.sh`): `ENABLE_CAPABILITY_WEIGHTING`, `ENABLE_CAPABILITY_ROUTING` (both false), `CAPABILITY_WEIGHT_STRENGTH` (10), `CAPABILITY_DEFAULT` (5). **Observability**: `consult_all.sh` records `capability{weighting_enabled, routing_enabled, axis}` in `optimization_metrics.json`.
844
+ - **Tests**: `test_capability_weighting` (17), `test_roster_audit` (6), `test_roster_calibrate` (10), `test_taste_elo` (6) — 12 suites total. All opt-in; with flags off, existing voting/routing/parity tests pass unchanged. shellcheck clean.
845
+ - **Docs**: `SMART_ROUTING.md` (capability + roster-audit + measured-calibration sections), `.env.example`, `references/configuration.md`, env-var table + structure list here. Website feature card added (sync on push).
846
+ - **Seeds are subjective** (Claude/Codex grounded on the model-routing table; the rest heuristic) — the calibration workflow measures them empirically. Fully back-compat.
847
+
829
848
  ### v2.19.2
830
849
  - **Cost tracking silently lost on a fresh install — fixed.** `lib/costs.sh::track_session_cost` wrote to `$COST_TRACKING_FILE` (`$XDG_DATA_HOME/ai-consultants/costs.json`, i.e. `~/.local/share/...`) without ever creating the parent directory. That dir doesn't exist until something makes it, and `costs.json` is the only artifact stored there — so on a fresh install every session's cost write failed with "No such file or directory" (swallowed under `set -e` in the caller) and cumulative cost tracking never accumulated. Fix: `mkdir -p "$(dirname "$COST_TRACKING_FILE")"` up front; on failure, `log_warn` + `return 0`.
831
850
  - **Function split for lock discipline**: `track_session_cost` (outer) now owns dir creation + locking and delegates the read-modify-write to a new inner `_track_session_cost_update`, which runs with the lock held and never propagates failure. Rationale documented inline: the caller in `consult_all.sh` runs under `set -e` *after* every consultant has already been queried and billed, so a bookkeeping failure must degrade to a warning, never abort the run.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # AI Consultants v2.19.2
1
+ # AI Consultants v2.20.0
2
2
 
3
3
  > **A harness for every question.** A panel of up to 15 frontier models that writes its own playbook per question — fan out, debate to convergence, cross-examine under adversarial review, or run a tournament — and checks its work before it reaches you.
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.19.2-blue.svg)](https://github.com/matteoscurati/ai-consultants)
5
+ [![Version](https://img.shields.io/badge/version-2.20.0-blue.svg)](https://github.com/matteoscurati/ai-consultants)
6
6
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![Claude Code Skill](https://img.shields.io/badge/Claude%20Code-Skill-orange.svg)](https://docs.anthropic.com/en/docs/claude-code/skills)
8
8
  [![GitHub stars](https://img.shields.io/github/stars/matteoscurati/ai-consultants?style=social)](https://github.com/matteoscurati/ai-consultants)
package/SKILL.md CHANGED
@@ -5,10 +5,10 @@ license: MIT
5
5
  compatibility: Requires bash, jq, and at least 2 AI CLI tools (agy, codex, vibe, etc.). macOS and Linux.
6
6
  metadata:
7
7
  author: matteoscurati
8
- version: 2.19.2
8
+ version: 2.20.0
9
9
  ---
10
10
 
11
- # AI Consultants v2.19.2 - AI Expert Panel
11
+ # AI Consultants v2.20.0 - AI Expert Panel
12
12
 
13
13
  **A harness for every question.** Convene a panel of AI "consultants" for coding questions — and let the engine pick *how* they deliberate: a quick read, a convergence loop, an adversarial refutation gate, a tournament, or an exhaustive sweep. Each consultant has a **configurable persona** that shapes its analysis.
14
14
 
@@ -1,4 +1,4 @@
1
- # Cost Rates - AI Consultants v2.19.2
1
+ # Cost Rates - AI Consultants v2.20.0
2
2
 
3
3
  This page documents the per-token rates used by the cost tracking system.
4
4
 
@@ -46,13 +46,21 @@ customization possible without editing bash.
46
46
 
47
47
  ```json
48
48
  {
49
- "version": "1.0",
49
+ "version": "1.1",
50
50
  "default_score": 5,
51
51
  "general_score": 8,
52
+ "capability_default": 5,
52
53
  "known_consultants": ["Gemini", "Codex", "..."],
53
54
  "categories": {
54
55
  "CODE_REVIEW": { "Gemini": 7, "Codex": 10, "..." },
55
56
  "BUG_DEBUG": { "..." }
57
+ },
58
+ "capabilities": {
59
+ "Gemini": { "intelligence": 8, "taste": 8, "cost": 6 },
60
+ "Codex": { "intelligence": 8, "taste": 5, "cost": 4 }
61
+ },
62
+ "category_axis": {
63
+ "API_DESIGN": "taste", "CODE_REVIEW": "taste", "ALGORITHM": "intelligence"
56
64
  }
57
65
  }
58
66
  ```
@@ -119,6 +127,112 @@ COMPLEXITY_THRESHOLD_MEDIUM=6 # Score 4-6 = use standard models
119
127
 
120
128
  See [COST_RATES.md](COST_RATES.md) for model pricing by tier.
121
129
 
130
+ ## Capability-Aware Routing & Voting (v2.20+)
131
+
132
+ Beyond category *fit* (the affinity matrix), v1.1 of `affinity.json` adds a
133
+ per-consultant **capability** score on three axes (1-10): `intelligence`,
134
+ `taste`, and `cost`. A `category_axis` map names the quality axis each category
135
+ stresses — **taste** for design-shaped work (API_DESIGN, ARCHITECTURE,
136
+ CODE_REVIEW, GENERAL), **intelligence** otherwise.
137
+
138
+ Two opt-in features consume this:
139
+
140
+ - **`ENABLE_CAPABILITY_WEIGHTING`** — a consultant's vote weight becomes
141
+ `confidence × (S + capability) / S` (`S = CAPABILITY_WEIGHT_STRENGTH`, default
142
+ 10), so on a taste-shaped question a high-taste model's opinion counts for more.
143
+ - **`ENABLE_CAPABILITY_ROUTING`** — panel *eligibility* still uses raw affinity,
144
+ but the *sort rank* becomes `affinity + (capability − CAPABILITY_DEFAULT)`, so
145
+ under a size limit the quality axis reorders which eligible consultants make
146
+ the cut.
147
+
148
+ `cost` is an efficiency axis for budget-aware composition only — **never** a
149
+ vote weight (tie-break order: intelligence > taste > cost). Scores are
150
+ subjective, point-in-time seeds — re-derive them for your own panel. Helpers:
151
+ `get_capability <consultant> <axis>` and `get_category_axis <category>` in
152
+ `lib/routing.sh`.
153
+
154
+ ## Roster Audit — Uncorrelated Value (v2.20+)
155
+
156
+ Adding a consultant only helps if it says something the others don't. The
157
+ `scripts/roster_audit.sh` tool measures this across past consultations: a
158
+ consultant's approach is *distinct* in a round when its keyword set has low
159
+ Jaccard overlap (`< --threshold`, default 20%) with **every** other consultant
160
+ that round. A consultant that is rarely distinct is correlated with the panel —
161
+ a candidate to drop or down-weight; one that is often distinct earns its seat on
162
+ diversity.
163
+
164
+ ```bash
165
+ # audit specific consultation output dirs
166
+ ./scripts/roster_audit.sh /path/to/consultation_dir ...
167
+
168
+ # or the N most recent under the consultations base
169
+ ./scripts/roster_audit.sh --recent 30
170
+
171
+ # machine-readable
172
+ ./scripts/roster_audit.sh --json --recent 30
173
+ ```
174
+
175
+ Read-only; reuses the `voting.sh` keyword/Jaccard machinery. Consultations with
176
+ fewer than two responders are skipped (correlation is undefined). This is the
177
+ model-routing "before a new model earns a row" bar (contribute >=1 thing the
178
+ incumbents miss) applied to the consultation panel instead of a review lane.
179
+
180
+ ## Measured Calibration — Replacing the Heuristic Seeds (v2.20+)
181
+
182
+ The `capabilities` scores in `affinity.json` ship as subjective seeds. To
183
+ **measure** them instead of guessing, three tools derive each axis from data the
184
+ tool already produces — sliced by the same `category_axis` that consumes them:
185
+
186
+ | Tool | Derives | From |
187
+ |---|---|---|
188
+ | `scripts/roster_calibrate.sh` | intelligence, taste, cost (**Tier A**) | blind peer-review scores (sliced by axis) + observed `tokens_used` × catalog rate |
189
+ | `scripts/taste_elo.sh` | taste (**Tier B**) | pairwise LLM-as-judge Elo over taste-axis answers (removes peer self-bias) |
190
+ | `references/calibration_benchmark.json` | the question set | 50 questions, 5 per category, balanced across the two axes |
191
+ | `scripts/run_calibration.sh` | the data | runs the benchmark through the panel with `ENABLE_PEER_REVIEW=true`, then calibrates |
192
+
193
+ ### Workflow
194
+
195
+ ```bash
196
+ # 1. Collect data: run the benchmark through the full panel (real calls — costs money).
197
+ ./scripts/run_calibration.sh --limit 10 --dry-run # preview
198
+ ./scripts/run_calibration.sh # full 50-question run
199
+
200
+ # 2. Tier A: measured intelligence/taste/cost -> capabilities block
201
+ ./scripts/roster_calibrate.sh --recent 50 # print measured block
202
+ ./scripts/roster_calibrate.sh --recent 50 --write # merge into affinity.json (keeps unmeasured cells)
203
+
204
+ # 3. Tier B (optional): refine taste via pairwise-judge Elo
205
+ ./scripts/taste_elo.sh --recent 50 --write
206
+ ```
207
+
208
+ Both `roster_calibrate.sh` and `taste_elo.sh` also accept explicit consultation
209
+ dirs and `--json`, and back up `affinity.json` to `.bak` before `--write`.
210
+
211
+ ### How each axis is measured
212
+
213
+ - **cost** — mean *observed* `$/response` (`tokens_used` × catalog rate, 60/40
214
+ input/output split), rank-normalized so the cheapest = 10. This is cost per
215
+ *task* (verbosity + completion), not per-token sticker price — a terse pricey
216
+ model can still rank cheap.
217
+ - **intelligence / taste** — mean **blind peer-review** `quality_score` (already
218
+ 1-10), sliced by `category_axis`: intelligence = performance on
219
+ intelligence-axis categories, taste = on taste-axis categories.
220
+ - **taste (Tier B)** — taste has no ground truth, so `taste_elo.sh` measures it
221
+ *relative to a chosen judge*. Each pair of answers on a taste-axis question is
222
+ shown to the judge, which picks the better one on design taste only; wins feed
223
+ an Elo ranking. The judge is pluggable:
224
+ - `JUDGE_CLI` — CLI for the built-in judge (default `claude`).
225
+ - `TASTE_JUDGE_CMD` — external judge `cmd <ctx> <A.json> <B.json>` printing
226
+ `A`/`B` (used by tests and custom judges).
227
+
228
+ ### Companion: which consultants earn a seat
229
+
230
+ `roster_audit.sh` (above) answers *who to keep*; calibration answers *how much
231
+ each is worth per axis*. Together they make the roster data-driven: audit to
232
+ prune redundant consultants, calibrate to score the survivors, then enable
233
+ `ENABLE_CAPABILITY_WEIGHTING` / `ENABLE_CAPABILITY_ROUTING` to act on the
234
+ measured scores.
235
+
122
236
  ## Timeout per Category
123
237
 
124
238
  Timeouts optimized based on category complexity:
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.19.2",
2
+ "version": "2.20.0",
3
3
  "updated": "2026-06-24",
4
4
  "models": {
5
5
  "_comment_units": "All rates are USD per 1,000 tokens (per-1K). lib/costs.sh computes cost as (token_count / 1000) * rate, so every value here MUST be a per-1K rate = (provider $/1M price) / 1000. Do NOT paste $/MTok figures directly.",
@@ -0,0 +1,65 @@
1
+ # Release v2.20.0
2
+
3
+ **Date:** 2026-07-12
4
+ **Type:** Minor — capability-aware deliberation + measured roster calibration
5
+ **Previous:** v2.19.2
6
+
7
+ ## Highlights
8
+
9
+ - **Capability-aware voting & composition** — weight votes and rank the panel by each model's capability on the quality axis a question stresses (intelligence or taste). Opt-in.
10
+ - **Roster audit** — see which consultants add distinct value vs merely echo the panel.
11
+ - **Measured calibration** — derive the capability scores from data (blind peer review + observed cost + pairwise-judge Elo) instead of heuristics.
12
+ - Everything new is opt-in and additive: with the flags off, behavior is identical to v2.19.2.
13
+
14
+ ## What's New
15
+
16
+ ### Capability axes (`affinity.json` v1.1)
17
+
18
+ Beyond category *fit* (the affinity matrix), each consultant now has a `capabilities` score on three axes (1-10) and a `category_axis` map names the quality axis each category stresses — **taste** for API_DESIGN / ARCHITECTURE / CODE_REVIEW / GENERAL, **intelligence** otherwise.
19
+
20
+ | Flag (default off) | Effect |
21
+ |---|---|
22
+ | `ENABLE_CAPABILITY_WEIGHTING` | A consultant's vote weight becomes `confidence × (S + capability) / S` on the run's axis (`S = CAPABILITY_WEIGHT_STRENGTH`, default 10). |
23
+ | `ENABLE_CAPABILITY_ROUTING` | Panel *eligibility* still uses raw affinity, but eligible consultants are ranked by `affinity + capability`, so under a size limit the quality axis reorders who makes the cut. |
24
+
25
+ `cost` is a composition/budget axis only — never a vote weight (tie-break order: intelligence > taste > cost).
26
+
27
+ ### Roster audit — uncorrelated value
28
+
29
+ `scripts/roster_audit.sh` scores each consultant's *distinctiveness* across past consultations: an approach with low keyword overlap versus every other consultant that round is "distinct". A consultant rarely distinct is correlated with the panel (candidate to drop or down-weight); one often distinct earns its seat. Also available as `doctor.sh --roster-audit` and the `/ai-consultants:roster-audit` slash command. Read-only.
30
+
31
+ ### Measured calibration (Tier A + Tier B)
32
+
33
+ Replace the heuristic capability seeds with measurements, each derived from a signal the tool already records and sliced by the same `category_axis`:
34
+
35
+ - **`scripts/roster_calibrate.sh` (Tier A)** — intelligence/taste = mean **blind peer-review** score on that axis's categories; cost = mean **observed** `tokens_used` × catalog rate (60/40 split, rank-normalized, cheapest = 10 → cost per *task*, not per token).
36
+ - **`scripts/taste_elo.sh` (Tier B)** — taste via **pairwise LLM-as-judge Elo** on taste-axis answers (removes the peer panel's self-bias). Judge is pluggable: `JUDGE_CLI` (default `claude`) or `TASTE_JUDGE_CMD`.
37
+ - **`scripts/run_calibration.sh` + `references/calibration_benchmark.json`** — 50 questions (20 taste / 30 intelligence) run through the panel with `ENABLE_PEER_REVIEW=true`, then calibrated.
38
+
39
+ Both calibrators accept `--json` and `--write` (merge measured scores into `affinity.json`, backing it up first).
40
+
41
+ ## Breaking Changes
42
+
43
+ None. All features are opt-in; with the flags off, behavior is identical to v2.19.2. The shipped `capabilities` scores are subjective seeds (Claude/Codex grounded on the model-routing table, the rest heuristic) until you run the calibration workflow.
44
+
45
+ ## Upgrade Guide
46
+
47
+ ```bash
48
+ cd ~/.claude/skills/ai-consultants && git pull # or: npx ai-consultants@latest install
49
+ ```
50
+
51
+ Optional — measure capability scores for your own panel:
52
+
53
+ ```bash
54
+ ./scripts/run_calibration.sh # collect data (real calls; --limit to sample)
55
+ ./scripts/roster_calibrate.sh --write # Tier A: intelligence/taste/cost -> affinity.json
56
+ ./scripts/taste_elo.sh --write # Tier B: refine taste (optional)
57
+ ```
58
+
59
+ ## Commits
60
+
61
+ - `_______` feat: capability-aware voting/routing + roster audit + measured calibration (v2.20.0)
62
+
63
+ ## Contributors
64
+
65
+ - @matteoscurati
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-consultants",
3
- "version": "2.19.2",
3
+ "version": "2.20.0",
4
4
  "description": "A harness for every question - a panel of up to 15 AI models that picks its own deliberation strategy per question (convergence, adversarial verification, tournament) and checks its work before answering",
5
5
  "bin": {
6
6
  "ai-consultants": "bin/ai-consultants"
@@ -1,8 +1,10 @@
1
1
  {
2
- "version": "1.0",
2
+ "version": "1.1",
3
3
  "_comment": "Affinity scores per (category, consultant). 10 = perfect match, 1 = poor match. Lookup order: (1) consultant NOT in known_consultants -> default_score (5). (2) category present in 'categories' -> categories[category][consultant] (with cell-missing fallback to default_score=5). (3) category absent -> general_score (8). NOTE the asymmetry: a known consultant in an unknown category gets 8, but in a known category with no cell gets 5. Rationale: a missing cell in a known category is a configuration gap (caught by doctor.sh) and should de-rank the consultant; an unknown category is just unmapped routing and treats all known consultants equally. To override at runtime: AFFINITY_FILE=/path/to/custom.json.",
4
+ "_comment_capabilities": "v1.1: per-consultant capability axes (1-10, higher=better) in 'capabilities', plus 'category_axis' mapping each question category to the quality axis it stresses. intelligence + taste are QUALITY axes: they weight votes (voting.sh, ENABLE_CAPABILITY_WEIGHTING) and rank the panel (routing.sh, ENABLE_CAPABILITY_ROUTING). cost is an EFFICIENCY axis for budget-aware composition only and is NEVER a vote weight (tie-break order: intelligence > taste > cost). Missing consultant/axis -> capability_default. Both features are OPT-IN and additive: with the flags off, behavior is identical to v1.0. These scores are SUBJECTIVE point-in-time seeds — re-derive them for your own panel (see the model-routing methodology): Claude (claude-opus-4-8) and Codex (gpt-5.5) axes are grounded on the author's model-routing table; the other consultants' axes are heuristic seeds pending measurement. Unmapped category_axis -> intelligence.",
4
5
  "default_score": 5,
5
6
  "general_score": 8,
7
+ "capability_default": 5,
6
8
  "known_consultants": [
7
9
  "Gemini", "Codex", "Mistral", "Kilo", "Cursor", "Aider",
8
10
  "Amp", "Kimi", "Claude", "Qwen3", "GLM", "Grok", "DeepSeek", "MiniMax"
@@ -53,5 +55,33 @@
53
55
  "Amp": 8, "Kimi": 6, "Claude": 7, "Qwen3": 8, "GLM": 10, "Grok": 7,
54
56
  "DeepSeek": 8, "MiniMax": 7
55
57
  }
58
+ },
59
+ "capabilities": {
60
+ "Gemini": { "intelligence": 8, "taste": 8, "cost": 6 },
61
+ "Codex": { "intelligence": 8, "taste": 5, "cost": 4 },
62
+ "Mistral": { "intelligence": 6, "taste": 6, "cost": 6 },
63
+ "Kilo": { "intelligence": 6, "taste": 6, "cost": 6 },
64
+ "Cursor": { "intelligence": 6, "taste": 7, "cost": 6 },
65
+ "Aider": { "intelligence": 6, "taste": 5, "cost": 9 },
66
+ "Amp": { "intelligence": 7, "taste": 7, "cost": 5 },
67
+ "Kimi": { "intelligence": 6, "taste": 6, "cost": 6 },
68
+ "Claude": { "intelligence": 7, "taste": 8, "cost": 5 },
69
+ "Qwen3": { "intelligence": 7, "taste": 5, "cost": 8 },
70
+ "GLM": { "intelligence": 6, "taste": 5, "cost": 7 },
71
+ "Grok": { "intelligence": 7, "taste": 6, "cost": 7 },
72
+ "DeepSeek": { "intelligence": 8, "taste": 5, "cost": 9 },
73
+ "MiniMax": { "intelligence": 6, "taste": 6, "cost": 8 }
74
+ },
75
+ "category_axis": {
76
+ "API_DESIGN": "taste",
77
+ "ARCHITECTURE": "taste",
78
+ "GENERAL": "taste",
79
+ "CODE_REVIEW": "taste",
80
+ "ALGORITHM": "intelligence",
81
+ "SECURITY": "intelligence",
82
+ "BUG_DEBUG": "intelligence",
83
+ "DATABASE": "intelligence",
84
+ "TESTING": "intelligence",
85
+ "QUICK_SYNTAX": "intelligence"
56
86
  }
57
87
  }
@@ -0,0 +1,65 @@
1
+ {
2
+ "_comment": "Calibration benchmark for roster_calibrate.sh. ~5 questions per category across all 10 categories, balanced over the two capability axes (taste: API_DESIGN, ARCHITECTURE, CODE_REVIEW, GENERAL; intelligence: the rest). Run each through consult_all.sh with ENABLE_PEER_REVIEW=true (scripts/run_calibration.sh does this), then roster_calibrate the output dirs to derive measured intelligence/taste/cost. Questions are deliberately generic (no repo context) so the panel is scored on judgment, not codebase familiarity. Re-derive/extend for your own domain.",
3
+ "version": "1.0",
4
+ "questions": [
5
+ { "category": "ALGORITHM", "axis": "intelligence", "q": "Design an algorithm to find the k-th smallest element in the union of two sorted arrays in O(log(m+n)) time. Explain the invariant." },
6
+ { "category": "ALGORITHM", "axis": "intelligence", "q": "Maintain the running median of a stream of integers efficiently. Which data structures, and what is the per-update cost?" },
7
+ { "category": "ALGORITHM", "axis": "intelligence", "q": "Detect a cycle in a directed graph and return one concrete cycle. Compare an iterative and a recursive approach." },
8
+ { "category": "ALGORITHM", "axis": "intelligence", "q": "Deduplicate 10 billion 64-bit integers using at most 4 GB of RAM. Outline an approach and its trade-offs." },
9
+ { "category": "ALGORITHM", "axis": "intelligence", "q": "Implement an LRU cache with O(1) get and put. Justify the data-structure choices and the failure modes." },
10
+
11
+ { "category": "BUG_DEBUG", "axis": "intelligence", "q": "A Node.js service leaks memory slowly under sustained load. Describe a systematic method to locate the leak." },
12
+ { "category": "BUG_DEBUG", "axis": "intelligence", "q": "Intermittent 'connection reset' errors appear only in production behind a load balancer. How do you diagnose the root cause?" },
13
+ { "category": "BUG_DEBUG", "axis": "intelligence", "q": "A unit test passes locally but fails ~10% of the time in CI. How do you find and fix the flakiness?" },
14
+ { "category": "BUG_DEBUG", "axis": "intelligence", "q": "After a deploy, p99 latency doubled while p50 is unchanged. Where do you look, and in what order?" },
15
+ { "category": "BUG_DEBUG", "axis": "intelligence", "q": "A Python multiprocessing script deadlocks occasionally. Enumerate likely causes and how to confirm each." },
16
+
17
+ { "category": "SECURITY", "axis": "intelligence", "q": "A web app stores session tokens in localStorage. Assess the risk and recommend a safer alternative with reasoning." },
18
+ { "category": "SECURITY", "axis": "intelligence", "q": "Design a secure password-reset flow. Enumerate the attacks it must resist and how each is mitigated." },
19
+ { "category": "SECURITY", "axis": "intelligence", "q": "How do you prevent SSRF in a service that fetches user-supplied URLs? Cover the non-obvious bypasses." },
20
+ { "category": "SECURITY", "axis": "intelligence", "q": "Review a JWT setup using HS256 with one shared secret across all services. What are the risks and fixes?" },
21
+ { "category": "SECURITY", "axis": "intelligence", "q": "Beyond parameterized queries, what controls reduce SQL-injection risk in a large codebase?" },
22
+
23
+ { "category": "QUICK_SYNTAX", "axis": "intelligence", "q": "In Python, what is the idiomatic way to merge two dictionaries with the second overriding the first?" },
24
+ { "category": "QUICK_SYNTAX", "axis": "intelligence", "q": "In JavaScript, explain == vs === with a concrete gotcha example." },
25
+ { "category": "QUICK_SYNTAX", "axis": "intelligence", "q": "In Java, how do you remove items from a list while iterating without a ConcurrentModificationException?" },
26
+ { "category": "QUICK_SYNTAX", "axis": "intelligence", "q": "In Bash, how do you distinguish an unset variable from an empty one?" },
27
+ { "category": "QUICK_SYNTAX", "axis": "intelligence", "q": "In Go, what is the idiomatic way to convert a slice of ints to a slice of strings?" },
28
+
29
+ { "category": "DATABASE", "axis": "intelligence", "q": "A JOIN across two 10M-row tables is slow. Walk through your indexing and diagnosis steps." },
30
+ { "category": "DATABASE", "axis": "intelligence", "q": "When would you denormalize a schema, and what consistency trade-offs does it introduce?" },
31
+ { "category": "DATABASE", "axis": "intelligence", "q": "Design multi-tenant storage: shared tables vs schema-per-tenant vs database-per-tenant. Recommend with reasoning." },
32
+ { "category": "DATABASE", "axis": "intelligence", "q": "Implement pagination that stays correct and fast on a frequently-updated table. What breaks with OFFSET?" },
33
+ { "category": "DATABASE", "axis": "intelligence", "q": "How do you choose between a B-tree and a hash index? Give a concrete example favoring each." },
34
+
35
+ { "category": "TESTING", "axis": "intelligence", "q": "For a payment service, how do you decide what to unit-test vs integration-test?" },
36
+ { "category": "TESTING", "axis": "intelligence", "q": "Design a testing strategy for a function with heavy date/time logic across time zones and DST." },
37
+ { "category": "TESTING", "axis": "intelligence", "q": "How do you test code that calls a flaky third-party API without hitting it in CI?" },
38
+ { "category": "TESTING", "axis": "intelligence", "q": "Propose a coverage-target policy that avoids gaming the metric while still catching regressions." },
39
+ { "category": "TESTING", "axis": "intelligence", "q": "Design property-based tests for a JSON serializer/deserializer round-trip. What invariants do you assert?" },
40
+
41
+ { "category": "CODE_REVIEW", "axis": "taste", "q": "Critique a function that takes 8 positional boolean parameters and propose a cleaner interface." },
42
+ { "category": "CODE_REVIEW", "axis": "taste", "q": "A 500-line module mixes business logic, HTTP handling, and SQL. How would you restructure it, and why?" },
43
+ { "category": "CODE_REVIEW", "axis": "taste", "q": "What makes error handling in a library 'good'? Compare returning null, throwing, and result types." },
44
+ { "category": "CODE_REVIEW", "axis": "taste", "q": "Booleans are named flag, check, and status throughout a codebase. Propose naming principles for a review guide." },
45
+ { "category": "CODE_REVIEW", "axis": "taste", "q": "When is a comment a code smell? Give concrete guidance for a team's review checklist." },
46
+
47
+ { "category": "ARCHITECTURE", "axis": "taste", "q": "Design the module boundaries for a URL-shortener service. Where are the seams and why there?" },
48
+ { "category": "ARCHITECTURE", "axis": "taste", "q": "Monolith vs microservices for a 5-engineer startup shipping B2B SaaS. Recommend and defend the choice." },
49
+ { "category": "ARCHITECTURE", "axis": "taste", "q": "Design an event-driven architecture for order processing. Where do you place consistency boundaries?" },
50
+ { "category": "ARCHITECTURE", "axis": "taste", "q": "How would you structure a shared design-system component library used by six product teams?" },
51
+ { "category": "ARCHITECTURE", "axis": "taste", "q": "Propose a caching strategy (layers, invalidation, keys) for a read-heavy content platform." },
52
+
53
+ { "category": "API_DESIGN", "axis": "taste", "q": "Design a REST API for a commenting system with threads, replies, and reactions. Show the resource model." },
54
+ { "category": "API_DESIGN", "axis": "taste", "q": "Offset vs cursor pagination for a public API. Recommend one and design the request/response contract." },
55
+ { "category": "API_DESIGN", "axis": "taste", "q": "How should an API represent partial updates? Compare PATCH strategies and design a clean one." },
56
+ { "category": "API_DESIGN", "axis": "taste", "q": "Design error responses for a public JSON API so clients can handle failures programmatically." },
57
+ { "category": "API_DESIGN", "axis": "taste", "q": "Version a public API without breaking clients. Compare URL vs header versioning and recommend." },
58
+
59
+ { "category": "GENERAL", "axis": "taste", "q": "What principles keep a fast-growing codebase maintainable over three years?" },
60
+ { "category": "GENERAL", "axis": "taste", "q": "How do you decide whether to adopt a new framework or stay on the current stack?" },
61
+ { "category": "GENERAL", "axis": "taste", "q": "What makes a good pull-request description? Provide a template and the rationale behind each part." },
62
+ { "category": "GENERAL", "axis": "taste", "q": "How should a team balance shipping speed against technical debt? Give a concrete, enforceable policy." },
63
+ { "category": "GENERAL", "axis": "taste", "q": "What is your approach to writing documentation that developers actually read and keep current?" }
64
+ ]
65
+ }
@@ -249,6 +249,23 @@ ENABLE_DEBATE_OPTIMIZATION=false # Skip debate if all agree
249
249
  ENABLE_COMPACT_REPORT=true # Summaries only in reports
250
250
  ```
251
251
 
252
+ ## Capability-Aware Routing & Voting (v2.20+)
253
+
254
+ Weight each consultant's vote (and rank the panel) by its capability on the
255
+ quality axis a question stresses — **intelligence** or **taste**, per the
256
+ `category_axis` map in [`references/affinity.json`](../references/affinity.json).
257
+ Per-consultant scores live in that file's `capabilities` block. `cost` is a
258
+ composition/budget axis only and is never a vote weight (tie-break order:
259
+ intelligence > taste > cost). Both features are opt-in and additive — with the
260
+ flags off, behavior is identical to before.
261
+
262
+ ```bash
263
+ ENABLE_CAPABILITY_WEIGHTING=false # capability-weighted voting
264
+ ENABLE_CAPABILITY_ROUTING=false # capability-aware panel composition
265
+ CAPABILITY_WEIGHT_STRENGTH=10 # higher = gentler nudge: weight = conf*(S+cap)/S
266
+ CAPABILITY_DEFAULT=5 # fallback for a missing consultant/axis
267
+ ```
268
+
252
269
  ## Timeouts and Retries
253
270
 
254
271
  ```bash
package/scripts/config.sh CHANGED
@@ -543,6 +543,18 @@ USE_ECONOMIC_MODELS_FOR_SIMPLE="${USE_ECONOMIC_MODELS_FOR_SIMPLE:-true}"
543
543
  COMPLEXITY_THRESHOLD_SIMPLE="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
544
544
  COMPLEXITY_THRESHOLD_MEDIUM="${COMPLEXITY_THRESHOLD_MEDIUM:-6}"
545
545
 
546
+ # --- Capability-Aware Routing & Voting (opt-in, v2.20) ---
547
+ # Weight each consultant's vote (and rank the panel) by its capability on the
548
+ # quality axis a question stresses — intelligence or taste, per
549
+ # references/affinity.json 'category_axis'. Scores live in affinity.json
550
+ # 'capabilities'. cost is a composition/budget axis only, never a vote weight
551
+ # (tie-break: intelligence > taste > cost). Both default off -> identical to
552
+ # prior behavior.
553
+ ENABLE_CAPABILITY_WEIGHTING="${ENABLE_CAPABILITY_WEIGHTING:-false}" # capability-weighted voting
554
+ ENABLE_CAPABILITY_ROUTING="${ENABLE_CAPABILITY_ROUTING:-false}" # capability-aware panel composition
555
+ CAPABILITY_WEIGHT_STRENGTH="${CAPABILITY_WEIGHT_STRENGTH:-10}" # higher = gentler nudge: weight = conf*(S+cap)/S
556
+ CAPABILITY_DEFAULT="${CAPABILITY_DEFAULT:-5}" # fallback capability for a missing consultant/axis
557
+
546
558
  # --- Selective Context ---
547
559
  # Send only relevant files to each consultant
548
560
  ENABLE_SELECTIVE_CONTEXT="${ENABLE_SELECTIVE_CONTEXT:-false}"
@@ -887,4 +899,4 @@ EOF
887
899
  # VERSION
888
900
  # =============================================================================
889
901
 
890
- AI_CONSULTANTS_VERSION="2.19.2"
902
+ AI_CONSULTANTS_VERSION="2.20.0"
@@ -786,6 +786,9 @@ jq -n \
786
786
  --arg orch_shape "${ORCH_SHAPE:-fixed}" \
787
787
  --argjson complexity "${QUERY_COMPLEXITY:-5}" \
788
788
  --arg intent "${QUERY_INTENT:-advise}" \
789
+ --arg cap_axis "$(get_category_axis "$QUESTION_CATEGORY" 2>/dev/null || echo "")" \
790
+ --argjson cap_weighting "${ENABLE_CAPABILITY_WEIGHTING:-false}" \
791
+ --argjson cap_routing "${ENABLE_CAPABILITY_ROUTING:-false}" \
789
792
  '{
790
793
  optimization_settings: {
791
794
  cache_enabled: $cache_enabled,
@@ -801,6 +804,11 @@ jq -n \
801
804
  complexity: $complexity,
802
805
  intent: $intent
803
806
  },
807
+ capability: {
808
+ weighting_enabled: $cap_weighting,
809
+ routing_enabled: $cap_routing,
810
+ axis: $cap_axis
811
+ },
804
812
  quality_metrics: {
805
813
  consensus_score: $consensus,
806
814
  consensus_level: $consensus_level,
package/scripts/doctor.sh CHANGED
@@ -34,6 +34,7 @@ SUGGEST_CONFIG=false
34
34
  SUGGEST_PRESET=false
35
35
  LIVE_MODE=false
36
36
  QUESTION=""
37
+ ROSTER_AUDIT=false
37
38
 
38
39
  while [[ $# -gt 0 ]]; do
39
40
  case "$1" in
@@ -65,6 +66,10 @@ while [[ $# -gt 0 ]]; do
65
66
  LIVE_MODE=true
66
67
  shift
67
68
  ;;
69
+ --roster-audit)
70
+ ROSTER_AUDIT=true
71
+ shift
72
+ ;;
68
73
  --question)
69
74
  QUESTION="${2:-}"
70
75
  shift 2
@@ -86,6 +91,8 @@ while [[ $# -gt 0 ]]; do
86
91
  echo " --live Send a real ping query to each enabled consultant"
87
92
  echo " (catches installed-but-unauthenticated CLIs that the"
88
93
  echo " static check reports as healthy). Costs a tiny query each."
94
+ echo " --roster-audit Audit past consultations for uncorrelated value"
95
+ echo " (which consultants add distinct signal vs echo the panel)"
89
96
  exit 0
90
97
  ;;
91
98
  *)
@@ -1183,4 +1190,12 @@ if [[ "$LIVE_MODE" == "true" ]]; then
1183
1190
  [[ ${#ISSUES[@]} -gt 0 ]] && exit 1 || exit 0
1184
1191
  fi
1185
1192
 
1193
+ if [[ "$ROSTER_AUDIT" == "true" ]]; then
1194
+ # Delegate to the standalone audit tool (reuses doctor's --json flag).
1195
+ audit_args=()
1196
+ [[ "$JSON_OUTPUT" == "true" ]] && audit_args+=(--json)
1197
+ "$SCRIPT_DIR/roster_audit.sh" ${audit_args[@]+"${audit_args[@]}"}
1198
+ exit $?
1199
+ fi
1200
+
1186
1201
  main