@bramburn/pi-model-council 1.6.2 → 1.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Bhavesh Ramburn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,460 @@
1
+ # model-council
2
+
3
+ Pi extension for multi-model coding decisions via OpenRouter.
4
+
5
+ Ask three independent AI models for a second opinion, then have a fourth model synthesise them into a single actionable plan. Use the fast `/opinion` command for quick checks, and `/council` for higher-stakes architectural decisions.
6
+
7
+ ## Features
8
+
9
+ - **Multi-model council** — Three OpenRouter models deliberate independently, then a fourth model (you pick) synthesises the final decision. Returned as a structured plan you (or Pi) can implement.
10
+ - **Single-model opinions** — Get a quick second opinion from any model with valid auth, using Pi's built-in model registry.
11
+ - **Pi-native auth** — Re-uses `OPENROUTER_API_KEY` (or `/login openrouter`) so the API key lives in one place. No separate key prompt required when Pi already knows OpenRouter.
12
+ - **Persistent settings** — Stored in `~/.pi/agent/council-settings.json` (or project-scoped when trusted). Includes the three council members, the synthesis model, and the opinion model.
13
+ - **Secure** — Settings are gitignored; keys never logged.
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ `pi install` accepts three source types: **npm**, **git**, and **local path**. Pick the one that matches how you want to consume the extension.
20
+
21
+ ### Prerequisites
22
+
23
+ - **Pi** installed (`pi --version` should print ≥ 1.0)
24
+ - **Node.js 22+** (matches the extension's CI runner)
25
+ - An **OpenRouter API key** — get one at [openrouter.ai/keys](https://openrouter.ai/keys)
26
+
27
+ ### Pick the install method
28
+
29
+ | Use case | Command | Where it lands |
30
+ |---|---|---|
31
+ | **npm** (recommended once published) | `pi install npm:pi-model-council` | `~/.pi/agent/npm/pi-model-council` |
32
+ | **GitHub via SSH** (most common) | `pi install git:github.com/bramburn/pi-model-council` | `~/.pi/agent/git/github.com/bramburn/pi-model-council` |
33
+ | **GitHub via HTTPS + PAT** (private repos, CI) | `pi install https://x-access-token:<TOKEN>@github.com/bramburn/pi-model-council.git` | `~/.pi/agent/git/github.com/bramburn/pi-model-council` |
34
+ | **Local clone** (development) | `pi install ./pi-model-council` | registered in-place, not copied |
35
+ | **Try without installing** (one-shot) | `pi -e git:github.com/bramburn/pi-model-council` | temp directory |
36
+
37
+ Pin to a specific tag for reproducibility (recommended for shared / CI use):
38
+
39
+ ```bash
40
+ pi install git:github.com/bramburn/pi-model-council@v1.5.0
41
+ ```
42
+
43
+ ### Detailed walkthroughs
44
+
45
+ #### Option 1 — npm (once the package is published)
46
+
47
+ ```bash
48
+ pi install npm:pi-model-council
49
+ ```
50
+
51
+ Updates use the regular npm flow: `pi update --extensions`.
52
+
53
+ #### Option 2 — GitHub via SSH
54
+
55
+ If you've already added an SSH key to your GitHub account (the same key you'd use for `git push` to this repo), Pi uses it automatically:
56
+
57
+ ```bash
58
+ pi install git:github.com/bramburn/pi-model-council
59
+ # Or pinned to a tag:
60
+ pi install git:github.com/bramburn/pi-model-council@v1.5.0
61
+ ```
62
+
63
+ The clone is placed under `~/.pi/agent/git/github.com/bramburn/pi-model-council/`.
64
+
65
+ #### Option 3 — GitHub via HTTPS with a Personal Access Token
66
+
67
+ Use this when SSH isn't an option. Create a **fine-grained** token at <https://github.com/settings/tokens?type=beta> with **read** access scoped to just `bramburn/pi-model-council`:
68
+
69
+ ```bash
70
+ pi install https://x-access-token:<TOKEN>@github.com/bramburn/pi-model-council.git
71
+ ```
72
+
73
+ > The PAT will be embedded in `~/.pi/agent/settings.json`. The settings file is created with `0600` permissions, but treat it as a secret and don't commit it.
74
+
75
+ #### Option 4 — Local clone (recommended for development)
76
+
77
+ ```bash
78
+ # Clone once anywhere
79
+ git clone https://github.com/bramburn/pi-model-council.git ~/code/pi-model-council
80
+ cd ~/code/pi-model-council
81
+ npm install
82
+
83
+ # Register the local path with pi (no copy — edits take effect immediately)
84
+ pi install ./pi-model-council
85
+ ```
86
+
87
+ To update later:
88
+
89
+ ```bash
90
+ cd ~/code/pi-model-council
91
+ git pull && npm install
92
+ # The next pi launch picks up the new code automatically; no reinstall needed.
93
+ # If you changed pi-extension metadata, force a refresh:
94
+ pi update --self --force
95
+ ```
96
+
97
+ #### Option 5 — Try without installing (one-shot smoke test)
98
+
99
+ ```bash
100
+ pi -e git:github.com/bramburn/pi-model-council
101
+ ```
102
+
103
+ Pi clones to a temp directory and uses the extension for the current run only. Nothing is written to your settings.
104
+
105
+ ### Project-scoped install (team sharing)
106
+
107
+ By default, `pi install` writes to **user** settings (`~/.pi/agent/settings.json`). To write to **project** settings (`.pi/settings.json`) so the install is checked into your team's repo and auto-applied when a teammate opens the project:
108
+
109
+ ```bash
110
+ pi install -l git:github.com/bramburn/pi-model-council@v1.5.0
111
+ ```
112
+
113
+ After this, commit `.pi/settings.json` to your project. When a teammate clones and Pi trusts the project, the extension installs automatically.
114
+
115
+ ### Verify the install
116
+
117
+ ```bash
118
+ pi list # shows installed packages and their sources
119
+ pi config # toggle the extension on/off
120
+ ```
121
+
122
+ You should see `pi-model-council` listed and enabled. Then launch Pi and try:
123
+
124
+ ```bash
125
+ pi
126
+ > /council-settings
127
+ ```
128
+
129
+ If the council UI opens, the extension is loaded correctly.
130
+
131
+ ### Updating an installed version
132
+
133
+ ```bash
134
+ # Update every installed extension to the ref pinned in settings
135
+ pi update --extensions
136
+
137
+ # Update only this one to a new tag/commit
138
+ pi install git:github.com/bramburn/pi-model-council@v1.6.0 # overwrites
139
+ ```
140
+
141
+ ### Uninstalling
142
+
143
+ ```bash
144
+ pi remove pi-model-council
145
+ ```
146
+
147
+ Or manually delete the entry from `~/.pi/agent/settings.json` and remove the clone under `~/.pi/agent/git/github.com/bramburn/pi-model-council/`. Your settings file (`council-settings.json`) is kept — re-installing will pick them back up.
148
+
149
+ ---
150
+
151
+ ## Workflow: Getting Started in 3 Steps
152
+
153
+ The whole setup takes about a minute. Follow this order — each step builds on the previous one.
154
+
155
+ ### Step 1 — Authenticate with OpenRouter (one-time)
156
+
157
+ Pi already ships with an OpenRouter provider. Give it your API key once and Pi will list every supported OpenRouter model under `provider === "openrouter"`.
158
+
159
+ ```bash
160
+ # Option A — environment variable (recommended for CI / dotfiles)
161
+ export OPENROUTER_API_KEY="sk-or-v1-..."
162
+
163
+ # Option B — interactive login (stores in ~/.pi/agent/auth.json with 0600 perms)
164
+ # Inside Pi, run:
165
+ /login openrouter
166
+ ```
167
+
168
+ Get a key from [openrouter.ai/keys](https://openrouter.ai/keys).
169
+
170
+ Verify Pi sees the models:
171
+
172
+ ```bash
173
+ pi --list-models
174
+ # Look for entries like:
175
+ # openrouter/anthropic/claude-3.5-sonnet
176
+ # openrouter/openai/gpt-4o
177
+ # openrouter/qwen/qwen3.7-max
178
+ ```
179
+
180
+ ### Step 2 — Configure the extension
181
+
182
+ Run the council settings UI. Pi will detect OpenRouter in your model registry and skip the API-key prompt entirely.
183
+
184
+ ```bash
185
+ /council-settings
186
+ ```
187
+
188
+ The UI uses a **typeahead-searchable, scrollable picker** (same UX as `/model`), so you can filter through hundreds of OpenRouter models by typing a few characters — fuzzy-matched across model name and id. Up/Down to navigate, Enter to select, Esc to cancel.
189
+
190
+ The UI walks you through:
191
+
192
+ 1. **Council Model 1 of 3** — first dissenting voice
193
+ 2. **Council Model 2 of 3** — second dissenting voice (already-picked models are filtered out)
194
+ 3. **Council Model 3 of 3** — third dissenting voice
195
+ 4. **Synthesis Model** — reads all three opinions and writes the final plan. Defaults to "Council Model 1" since you already trust it; pick any OpenRouter model you like.
196
+ 5. **Second Opinion Model** — the model used by `/opinion` for quick checks
197
+ 6. **Structured Output** — JSON schema for faster parsing (recommended: yes)
198
+
199
+ If Pi doesn't see OpenRouter yet (because you skipped Step 1), the UI falls back to a manual flow: it asks for an API key, pings OpenRouter to verify, fetches the live model list, and proceeds the same way.
200
+
201
+ Re-run anytime to swap models:
202
+
203
+ ```bash
204
+ /council-settings list # show current config
205
+ /council-settings reset # wipe and reconfigure
206
+ ```
207
+
208
+ For just the opinion model:
209
+
210
+ ```bash
211
+ /opinion-settings
212
+ ```
213
+
214
+ ### Step 3 — Use the council
215
+
216
+ ```bash
217
+ # Three deliberating models + one synthesis model
218
+ /council fix "The login fails on mobile devices"
219
+ /council ask "Should we use hooks or context for state?"
220
+ /council architecture "Where should auth state live?"
221
+
222
+ # Single-model quick check (uses your /opinion model)
223
+ /opinion "How should I refactor this function?"
224
+ /opinion fix "Lesson progress resets after navigation"
225
+ ```
226
+
227
+ The full report is saved to `.pi/council/last-decision.md` (and `.pi/council/last-opinion.md` for `/opinion`). The Pi agent can read this file when continuing the conversation.
228
+
229
+ ---
230
+
231
+ ## How Model Selection Works
232
+
233
+ The extension uses two layers:
234
+
235
+ | Layer | Source | Purpose |
236
+ |---|---|---|
237
+ | **Discovery** | `ctx.modelRegistry.getAvailable()` | Lists every OpenRouter model Pi knows about (the curated list ships with Pi). Filtered to `provider === "openrouter"`. |
238
+ | **Validation** | Same registry, then OpenRouter `/models` fallback | Confirms each chosen model ID still exists at runtime. |
239
+ | **Inference** | Direct OpenRouter REST call (`openrouterClient.ts`) | Sends the council prompts to each model and the synthesis prompt to the chosen synthesiser. |
240
+
241
+ This means:
242
+
243
+ - If Pi already knows about OpenRouter (Step 1 above), `ctx.modelRegistry.getAvailable()` provides the model list — no extra HTTP call.
244
+ - If the registry is empty (e.g. fresh install, no API key yet), the UI prompts for a key and fetches the live model list directly from OpenRouter.
245
+ - The chosen model IDs are stored in `council-settings.json` and used to make the actual inference calls. They are not changed when you swap Pi providers.
246
+
247
+ ### Why a separate Synthesis Model?
248
+
249
+ The three council members argue from different angles; the synthesis model is the judge that weighs them and produces a single plan. By default it's "Council Model 1" because you already trust that model. For higher-stakes decisions, pick a model known for careful reasoning (e.g. `anthropic/claude-3.5-sonnet`, `openai/o1`) — it's a 4th API call on top of the three council calls.
250
+
251
+ ### The 4-Model Orchestration Flow
252
+
253
+ When you run `/council`, a single `council_decide` tool call internally fans out to four models. Pi sees only the final synthesised report — all sub-calls are hidden behind one logical tool:
254
+
255
+ ```
256
+ /council fix "..." (slash command)
257
+
258
+
259
+ ┌───────────────────────────────┐
260
+ │ council_decide tool │ (single Pi tool call)
261
+ │ councilRunner.ts │
262
+ └───────────────────────────────┘
263
+
264
+ ┌─────────────────┼─────────────────┐
265
+ │ │ │
266
+ ▼ ▼ ▼
267
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
268
+ │ Model 1 │ │ Model 2 │ │ Model 3 │ ← Promise.all
269
+ │ (council)│ │ (council)│ │ (council)│ parallel
270
+ └────┬─────┘ └────┬─────┘ └────┬─────┘ fan-out
271
+ │ │ │
272
+ ▼ ▼ ▼
273
+ opinion A opinion B opinion C (JSON)
274
+ │ │ │
275
+ └──────────────────┼──────────────────┘
276
+
277
+ ┌──────────────┐
278
+ │ Model 4 │ ← synthesis step
279
+ │ (synthesis) │ reads 3 opinions
280
+ └──────┬───────┘ writes 1 decision
281
+
282
+ ┌──────────────┐
283
+ │ Pi receives │ ← tool result returned to agent
284
+ │ Markdown │
285
+ │ report │
286
+ └──────────────┘
287
+ ```
288
+
289
+ **Key properties:**
290
+
291
+ - All four calls happen **inside one tool execution**, so the agent sees a single tool call in its reasoning graph — no multi-turn coordination overhead.
292
+ - The three council calls run **in parallel** via `Promise.all`. Each call has its own `withTimeout` + `retry` wrapper, so a slow or failing model doesn't block the others.
293
+ - If 1 of 3 council models fails, the synthesis step still proceeds with the 2 successful opinions. If all 3 fail, the runner surfaces a clear error.
294
+ - The synthesis call has a longer timeout (`synthesisTimeoutMs`) because the synthesis prompt includes all three opinions.
295
+ - `ctx.signal` is threaded through every downstream `fetch()`, so pressing Esc during a long council cancels all in-flight calls (Pi's `withTimeout` helper combines the parent signal with per-call timeouts).
296
+
297
+ ### Where the API Key Comes From
298
+
299
+ Resolution order:
300
+
301
+ 1. `council-settings.json` → `openRouter.apiKey` (the legacy explicit-prompt flow)
302
+ 2. Pi's auth storage → `modelRegistry.getApiKeyForProvider("openrouter")` (when you've set `OPENROUTER_API_KEY` or run `/login openrouter`)
303
+ 3. `process.env.OPENROUTER_API_KEY`
304
+
305
+ If none of these resolve, `/council` and `/opinion` both fail fast with a setup error pointing you at `/council-settings`.
306
+
307
+ ---
308
+
309
+ ## Commands
310
+
311
+ ### `/council`
312
+
313
+ Three OpenRouter models + one synthesis model.
314
+
315
+ ```bash
316
+ /council fix "The login fails on mobile devices"
317
+ /council ask "Should we use hooks or context for state?"
318
+ /council architecture "Where should auth state live?"
319
+ ```
320
+
321
+ Modes:
322
+
323
+ - `fix` — debug a known problem
324
+ - `ask` — open technical question
325
+ - `architecture` — design-level decision
326
+ - (default) — generic second opinion
327
+
328
+ ### `/opinion`
329
+
330
+ Single-model quick check.
331
+
332
+ ```bash
333
+ /opinion "How should I refactor this function?"
334
+ /opinion fix "The lesson progress resets after navigation"
335
+ ```
336
+
337
+ Modes: `fix`, `ask`, `architecture`, `general`.
338
+
339
+ ### `/council-settings`
340
+
341
+ Configure the OpenRouter setup.
342
+
343
+ ```bash
344
+ /council-settings # Open the settings UI (3 council + 1 synthesis + opinion)
345
+ /council-settings list # Show current settings (API key redacted)
346
+ /council-settings reset # Reset all council settings
347
+ ```
348
+
349
+ ### `/opinion-settings`
350
+
351
+ Configure just the `/opinion` model.
352
+
353
+ ```bash
354
+ /opinion-settings # Open the settings UI
355
+ /opinion-settings list # Show current model
356
+ /opinion-settings reset # Reset to default
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Models
362
+
363
+ ### Council (3 Members)
364
+
365
+ The three models you pick in `/council-settings` for independent deliberation. Recommended starting set (all available on OpenRouter):
366
+
367
+ - `anthropic/claude-3.5-sonnet` — careful reasoning, code quality
368
+ - `openai/gpt-4o` — broad knowledge, multimodal
369
+ - `qwen/qwen3.7-max` — strong code model, cost-effective
370
+
371
+ Pick models that disagree productively. If they all share a training cutoff, you get correlated blind spots.
372
+
373
+ ### Synthesis Model
374
+
375
+ The fourth model that reads the three opinions and writes the single recommendation. Defaults to "Council Model 1". For high-stakes decisions, consider a reasoning-tuned model:
376
+
377
+ - `openai/o1` — strong step-by-step reasoning
378
+ - `anthropic/claude-3.5-sonnet` — careful, balanced
379
+ - `deepseek/deepseek-r1` — reasoning model with low cost
380
+
381
+ ### Second Opinion (`/opinion`)
382
+
383
+ Any model with valid auth works. Pi's `modelRegistry.getAvailable()` is the source of truth, so any provider you've configured (Anthropic, OpenAI, Google, OpenRouter, etc.) is selectable.
384
+
385
+ ---
386
+
387
+ ## Architecture
388
+
389
+ ```
390
+ pi-model-council/
391
+ ├── index.ts # Extension entry point
392
+ ├── councilRunner.ts # 3-model + synthesis logic
393
+ ├── secondOpinionRunner.ts # Single-model logic
394
+ ├── settings.ts # Settings persistence
395
+ ├── settings-ui.ts # Settings TUI components (registry-aware)
396
+ ├── openrouterClient.ts # OpenRouter REST client + JSON repair
397
+ ├── prompts.ts # Proposal + synthesis prompts (blind-label)
398
+ ├── structuredOutput.ts # JSON schemas + repair
399
+ ├── markdown.ts # Decision report formatter
400
+ ├── searchSelector.ts # Searchable model picker (custom TUI)
401
+ ├── retry.ts # Timeout + retry helpers
402
+ ├── schemas.ts # TypeBox tool parameter schemas
403
+ ├── commandParser.ts # CLI argument parsers
404
+ └── types.ts # Shared TypeScript types
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Development
410
+
411
+ ```bash
412
+ # Install dependencies
413
+ npm install
414
+
415
+ # Type check
416
+ npm run typecheck
417
+
418
+ # Lint
419
+ npm run lint
420
+
421
+ # Run tests
422
+ npm test
423
+
424
+ # Watch mode
425
+ npm run test:watch
426
+
427
+ # Coverage
428
+ npm run test:coverage
429
+
430
+ # Audit dependencies
431
+ npm run audit
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Security
437
+
438
+ See [SECURITY.md](SECURITY.md) for the security policy and reporting vulnerabilities.
439
+
440
+ API keys are stored in `council-settings.json` (when set explicitly) or in Pi's `~/.pi/agent/auth.json` (when set via env var or `/login`). Both files use `0600` permissions and are gitignored. The extension never logs keys, but does echo a redacted preview when listing settings.
441
+
442
+ ## Disclaimer
443
+
444
+ This extension sends your prompts to OpenRouter and the model providers behind it. AI-generated suggestions can be wrong, outdated, or unsafe — always review before applying. See [DISCLAIMER.md](DISCLAIMER.md) for the full text.
445
+
446
+ ## Contributing
447
+
448
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, code style, and the PR process.
449
+
450
+ ## Code of Conduct
451
+
452
+ By participating, you agree to the Contributor Covenant in [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
453
+
454
+ ## Support
455
+
456
+ Open an issue using the templates in [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/). See [SUPPORT.md](SUPPORT.md) for where to ask questions.
457
+
458
+ ## License
459
+
460
+ MIT — see [LICENSE](LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,80 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 0.x | :white_check_mark: |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ If you discover a security vulnerability, please report it via:
12
+
13
+ 1. **GitHub Security Advisories** (preferred):
14
+ https://github.com/bramburn/pi-model-council/security/advisories/new
15
+
16
+ 2. **Email**: (TBD - report via GitHub for now)
17
+
18
+ Please do NOT report security issues via public GitHub issues.
19
+
20
+ For critical vulnerabilities, we aim to respond within **48 hours** and publish a fix within **7 days**.
21
+
22
+ ## Security Best Practices (for users)
23
+
24
+ ### Protecting Your API Key
25
+
26
+ - **Never commit your `council-settings.json` to git** — it contains your OpenRouter API key
27
+ - The file is already in `.gitignore`, but verify it's not being tracked
28
+ - Run `git status` to check before any commit
29
+
30
+ ### Verifying the Extension
31
+
32
+ Before installing or updating:
33
+
34
+ 1. Review the source code in this repository
35
+ 2. Check the commit history for any suspicious changes
36
+ 3. Report concerns via GitHub Security Advisories
37
+
38
+ ### Keeping Dependencies Updated
39
+
40
+ The extension uses minimal dependencies. Keep them updated:
41
+
42
+ ```bash
43
+ npm run audit
44
+ npm update
45
+ ```
46
+
47
+ Or use the automatic Dependabot PRs that are created weekly.
48
+
49
+ ## Extension Security Notes
50
+
51
+ ### What This Extension Can Do
52
+
53
+ This extension runs with the same permissions as pi itself:
54
+ - Read and write files in your project
55
+ - Execute shell commands
56
+ - Call LLM APIs with your API keys
57
+
58
+ ### Trust Decision
59
+
60
+ When you first use this extension in a project, pi will ask if you trust the project. Only trust projects where:
61
+ - The `.pi/extensions/` directory is controlled by you
62
+ - No untrusted code can modify the extension files
63
+ - You're comfortable with the extension having full file system access
64
+
65
+ ## Incident Response
66
+
67
+ If you believe your API key has been compromised:
68
+
69
+ 1. **Revoke the key immediately** at https://openrouter.ai/keys
70
+ 2. **Generate a new key** at https://openrouter.ai/keys
71
+ 3. **Update your settings** via `/council-settings`
72
+ 4. **Report the incident** via GitHub Security Advisories
73
+
74
+ ## Security Dependencies
75
+
76
+ This extension is kept intentionally simple with minimal dependencies to reduce attack surface:
77
+
78
+ - `@sinclair/typebox` — JSON schema validation only
79
+ - No network calls except to OpenRouter API
80
+ - No shell command execution beyond what pi itself allows
package/SUPPORT.md ADDED
@@ -0,0 +1,72 @@
1
+ # Support
2
+
3
+ Need help with `pi-model-council`? Here's where to look.
4
+
5
+ ## Documentation
6
+
7
+ Start with [README.md](README.md) — it covers:
8
+
9
+ - The 3-step Quick Start workflow
10
+ - All four commands (`/council`, `/opinion`, `/council-settings`, `/opinion-settings`)
11
+ - How model selection works (Pi model registry vs OpenRouter REST)
12
+ - Where the API key is resolved from
13
+ - Architecture and development workflow
14
+
15
+ For deeper topics:
16
+
17
+ - [SECURITY.md](SECURITY.md) — Reporting vulnerabilities, API key hygiene
18
+ - [DISCLAIMER.md](DISCLAIMER.md) — AI accuracy, cost, third-party terms
19
+ - [CONTRIBUTING.md](CONTRIBUTING.md) — Setting up the project, PR process
20
+ - [CHANGELOG.md](CHANGELOG.md) — What changed in each release
21
+
22
+ ## Asking a question
23
+
24
+ **GitHub Discussions** is the preferred place for "how do I…?" questions. Search first; if your question isn't already answered, open a new discussion with:
25
+
26
+ - What you were trying to do
27
+ - The exact command you ran (e.g. `/council fix "..."`)
28
+ - What you expected to happen
29
+ - What actually happened (full error if any)
30
+ - Pi version, Node version, OS
31
+
32
+ ## Filing a bug
33
+
34
+ Use the **Bug report** template at
35
+ [`.github/ISSUE_TEMPLATE/bug_report.md`](.github/ISSUE_TEMPLATE/bug_report.md).
36
+ Include the same details as above plus a minimal reproduction.
37
+
38
+ ## Requesting a feature
39
+
40
+ Use the **Feature request** template at
41
+ [`.github/ISSUE_TEMPLATE/feature_request.md`](.github/ISSUE_TEMPLATE/feature_request.md).
42
+ Describe the use case first, then the proposed solution.
43
+
44
+ ## Security issues
45
+
46
+ **Do not open a public issue for security vulnerabilities.** Follow
47
+ [SECURITY.md](SECURITY.md) — use the GitHub Security Advisories page
48
+ (preferred) or email the maintainer privately.
49
+
50
+ ## Response times
51
+
52
+ This is a small project maintained on personal time. Expect:
53
+
54
+ - Bug reports — acknowledgement within a week, fix on a best-effort basis
55
+ - Feature requests — review and triage within a few weeks
56
+ - Security reports — within 48 hours per the policy in SECURITY.md
57
+
58
+ If you need a guaranteed response window, this project isn't a good fit; use a
59
+ commercial alternative.
60
+
61
+ ## Paid support
62
+
63
+ This project does not offer paid support. If you need urgent help integrating
64
+ `pi-model-council` into a commercial workflow, consider:
65
+
66
+ - Hiring a Pi-extension developer from the Pi community
67
+ - Forking the project and maintaining your own internal version
68
+
69
+ ## Code of Conduct
70
+
71
+ All community spaces (issues, discussions, PRs) are governed by our
72
+ [Code of Conduct](CODE_OF_CONDUCT.md). Be kind, be specific, be patient.