@statechange/council 0.1.0 → 0.3.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.
- package/README.md +126 -95
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/gui.d.ts +1 -0
- package/dist/commands/gui.js +63 -0
- package/dist/commands/gui.js.map +1 -0
- package/dist/commands/install.d.ts +5 -0
- package/dist/commands/install.js +131 -0
- package/dist/commands/install.js.map +1 -0
- package/dist-electron/index-B7VRloBj.js +1293 -0
- package/dist-electron/index-C03cLUYg.js +5911 -0
- package/dist-electron/index-Dw6I25AL.js +5911 -0
- package/dist-electron/index-NMn1koXq.js +31737 -0
- package/dist-electron/index-zpksia2X.js +5911 -0
- package/dist-electron/main-C_og2Wvn.js +32969 -0
- package/dist-electron/main-DBohq-SO.js +32969 -0
- package/dist-electron/main.js +791 -1217
- package/dist-electron/multipart-parser-Bdb1JOpV.js +353 -0
- package/dist-electron/multipart-parser-Cc_drctG.js +353 -0
- package/dist-electron/multipart-parser-Do9VIIY5.js +353 -0
- package/dist-electron/preload.mjs +1 -0
- package/dist-renderer/assets/Tableau10-B-NsZVaP.js +1 -0
- package/dist-renderer/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
- package/dist-renderer/assets/ar-SA-G6X2FPQ2-CNUtTBRd.js +10 -0
- package/dist-renderer/assets/arc-BsV2XMg-.js +1 -0
- package/dist-renderer/assets/array-BKyUJesY.js +1 -0
- package/dist-renderer/assets/az-AZ-76LH7QW2-BU-6SB21.js +1 -0
- package/dist-renderer/assets/bg-BG-XCXSNQG7-L1xMEEzs.js +5 -0
- package/dist-renderer/assets/blockDiagram-38ab4fdb-BHS1f8SU.js +118 -0
- package/dist-renderer/assets/bn-BD-2XOGV67Q-BgaYSNWB.js +5 -0
- package/dist-renderer/assets/c4Diagram-3d4e48cf-D2Rl9Buo.js +10 -0
- package/dist-renderer/assets/ca-ES-6MX7JW3Y-DsFYhkLC.js +8 -0
- package/dist-renderer/assets/channel-D6rvl4sk.js +1 -0
- package/dist-renderer/assets/classDiagram-70f12bd4-BGxDdVFC.js +2 -0
- package/dist-renderer/assets/classDiagram-v2-f2320105-BuoUwdmW.js +2 -0
- package/dist-renderer/assets/clone-ya1OS7ZU.js +1 -0
- package/dist-renderer/assets/createText-2e5e7dd3-BX6eAgL1.js +7 -0
- package/dist-renderer/assets/cs-CZ-2BRQDIVT-CXV-i633.js +11 -0
- package/dist-renderer/assets/da-DK-5WZEPLOC-DmYIifsm.js +5 -0
- package/dist-renderer/assets/de-DE-XR44H4JA-B2T52TzN.js +8 -0
- package/dist-renderer/assets/directory-open-01563666-DWU9wJ6I.js +1 -0
- package/dist-renderer/assets/directory-open-4ed118d0-CunoC1EB.js +1 -0
- package/dist-renderer/assets/edges-e0da2a9e-ChSiyO2u.js +4 -0
- package/dist-renderer/assets/el-GR-BZB4AONW-DlS_8ZJJ.js +10 -0
- package/dist-renderer/assets/erDiagram-9861fffd-REAc3tDU.js +51 -0
- package/dist-renderer/assets/es-ES-U4NZUMDT-DL-zHXpT.js +9 -0
- package/dist-renderer/assets/eu-ES-A7QVB2H4-Cq0Kx947.js +11 -0
- package/dist-renderer/assets/fa-IR-HGAKTJCU-DJqZOqAL.js +8 -0
- package/dist-renderer/assets/fi-FI-Z5N7JZ37-CQiIDJrs.js +6 -0
- package/dist-renderer/assets/file-open-002ab408-DIuFHtCF.js +1 -0
- package/dist-renderer/assets/file-open-7c801643-684qeFg4.js +1 -0
- package/dist-renderer/assets/file-save-3189631c-C1wFhQhH.js +1 -0
- package/dist-renderer/assets/file-save-745eba88-Bb9F9Kg7.js +1 -0
- package/dist-renderer/assets/flowDb-956e92f1-iZnRwdLd.js +10 -0
- package/dist-renderer/assets/flowDiagram-66a62f08-Cww5ErID.js +4 -0
- package/dist-renderer/assets/flowDiagram-v2-96b9c2cf-DMQnUrJv.js +1 -0
- package/dist-renderer/assets/flowchart-elk-definition-4a651766-B3GjdX0I.js +139 -0
- package/dist-renderer/assets/fr-FR-RHASNOE6-DXRyDBSp.js +9 -0
- package/dist-renderer/assets/ganttDiagram-c361ad54-Dh5UuCf5.js +257 -0
- package/dist-renderer/assets/gitGraphDiagram-72cf32ee-CUrdiK9f.js +70 -0
- package/dist-renderer/assets/gl-ES-HMX3MZ6V-DB2LhjQl.js +10 -0
- package/dist-renderer/assets/graph-KS9cHKTv.js +1 -0
- package/dist-renderer/assets/he-IL-6SHJWFNN-CWdud4mG.js +10 -0
- package/dist-renderer/assets/hi-IN-IWLTKZ5I-DkfCxaBI.js +4 -0
- package/dist-renderer/assets/hu-HU-A5ZG7DT2-DVX9rddx.js +7 -0
- package/dist-renderer/assets/id-ID-SAP4L64H-CIosyByg.js +10 -0
- package/dist-renderer/assets/image-blob-reduce.esm-BLtmMM_J.js +2 -0
- package/dist-renderer/assets/index-3862675e-CVxUAJo4.js +1 -0
- package/dist-renderer/assets/index-3RkkhxnO.js +36 -0
- package/dist-renderer/assets/index-B61Czmwn.js +95 -0
- package/dist-renderer/assets/index-BF6L2_KC.css +1 -0
- package/dist-renderer/assets/infoDiagram-f8f76790-CWACEGb6.js +7 -0
- package/dist-renderer/assets/init-Gi6I4Gst.js +1 -0
- package/dist-renderer/assets/it-IT-JPQ66NNP-D-TuMToN.js +11 -0
- package/dist-renderer/assets/ja-JP-DBVTYXUO-CK6puaHx.js +8 -0
- package/dist-renderer/assets/journeyDiagram-49397b02-DM-laNCt.js +139 -0
- package/dist-renderer/assets/kaa-6HZHGXH3-CiRWfMKd.js +1 -0
- package/dist-renderer/assets/kab-KAB-ZGHBKWFO-D4w9BQ8H.js +8 -0
- package/dist-renderer/assets/katex-DhXJpUyf.js +261 -0
- package/dist-renderer/assets/kk-KZ-P5N5QNE5-RZi2AGvr.js +1 -0
- package/dist-renderer/assets/km-KH-HSX4SM5Z-Dm-OPxhU.js +11 -0
- package/dist-renderer/assets/ko-KR-MTYHY66A-PbPGVqVz.js +9 -0
- package/dist-renderer/assets/ku-TR-6OUDTVRD-Bw0cMtYj.js +9 -0
- package/dist-renderer/assets/layout-zADYSvqS.js +1 -0
- package/dist-renderer/assets/line-DfBkzhQg.js +1 -0
- package/dist-renderer/assets/linear-O3lyK7Iz.js +1 -0
- package/dist-renderer/assets/lt-LT-XHIRWOB4-06ru_RZe.js +3 -0
- package/dist-renderer/assets/lv-LV-5QDEKY6T-DsGBjFui.js +7 -0
- package/dist-renderer/assets/mindmap-definition-fc14e90a-Bg9UaNPK.js +415 -0
- package/dist-renderer/assets/mr-IN-CRQNXWMA-C1kWOErC.js +13 -0
- package/dist-renderer/assets/my-MM-5M5IBNSE-C8wD2OFs.js +1 -0
- package/dist-renderer/assets/nb-NO-T6EIAALU-B7ac-R_W.js +10 -0
- package/dist-renderer/assets/nl-NL-IS3SIHDZ-Up67nxB7.js +8 -0
- package/dist-renderer/assets/nn-NO-6E72VCQL-BPlkzXM9.js +8 -0
- package/dist-renderer/assets/oc-FR-POXYY2M6-TRLIkgml.js +8 -0
- package/dist-renderer/assets/ordinal-BENe2yWM.js +1 -0
- package/dist-renderer/assets/pa-IN-N4M65BXN-Dl7hF9RX.js +4 -0
- package/dist-renderer/assets/path-CbwjOpE9.js +1 -0
- package/dist-renderer/assets/percentages-BXMCSKIN-wBXtRqNn.js +199 -0
- package/dist-renderer/assets/pica-CGZUgvhx.js +2 -0
- package/dist-renderer/assets/pieDiagram-8a3498a8-ZPRkRtpu.js +35 -0
- package/dist-renderer/assets/pl-PL-T2D74RX3-DkwkT852.js +9 -0
- package/dist-renderer/assets/pt-BR-5N22H2LF-BMFWH_jN.js +9 -0
- package/dist-renderer/assets/pt-PT-UZXXM6DQ-BPSC-yrG.js +9 -0
- package/dist-renderer/assets/quadrantDiagram-120e2f19-DB1TyNBK.js +7 -0
- package/dist-renderer/assets/requirementDiagram-deff3bca-DqVc_A29.js +52 -0
- package/dist-renderer/assets/ro-RO-JPDTUUEW-CgkEXyU-.js +11 -0
- package/dist-renderer/assets/roundRect-mAH3dD0p.js +1 -0
- package/dist-renderer/assets/ru-RU-B4JR7IUQ-BJIahd0q.js +9 -0
- package/dist-renderer/assets/sankeyDiagram-04a897e0-DZqGbQ0e.js +8 -0
- package/dist-renderer/assets/sequenceDiagram-704730f1-D0Q04jBP.js +122 -0
- package/dist-renderer/assets/si-LK-N5RQ5JYF-DZ97xsfW.js +1 -0
- package/dist-renderer/assets/sk-SK-C5VTKIMK-3O0GcaTE.js +6 -0
- package/dist-renderer/assets/sl-SI-NN7IZMDC-x_-Ca4Po.js +6 -0
- package/dist-renderer/assets/stateDiagram-587899a1-BkW3tbK-.js +1 -0
- package/dist-renderer/assets/stateDiagram-v2-d93cdb3a-CZYVILLk.js +1 -0
- package/dist-renderer/assets/styles-6aaf32cf-BQKVAqEs.js +207 -0
- package/dist-renderer/assets/styles-9a916d00-DTjDY-zu.js +160 -0
- package/dist-renderer/assets/styles-c10674c1-CviHLZ2K.js +116 -0
- package/dist-renderer/assets/subset-shared.chunk-DIxPfZhi.js +22 -0
- package/dist-renderer/assets/subset-worker.chunk-DDMwauN2.js +1 -0
- package/dist-renderer/assets/sv-SE-XGPEYMSR-DmtUCQiw.js +10 -0
- package/dist-renderer/assets/svgDrawCommon-08f97a94-B6bAmadW.js +1 -0
- package/dist-renderer/assets/ta-IN-2NMHFXQM-D7fiXwNW.js +9 -0
- package/dist-renderer/assets/th-TH-HPSO5L25-D_F5D_Tj.js +2 -0
- package/dist-renderer/assets/timeline-definition-85554ec2-BZuaxri2.js +61 -0
- package/dist-renderer/assets/tr-TR-DEFEU3FU-CzwSWbpN.js +7 -0
- package/dist-renderer/assets/uk-UA-QMV73CPH-BaaxaBLn.js +6 -0
- package/dist-renderer/assets/vi-VN-M7AON7JQ-BQ9szPme.js +5 -0
- package/dist-renderer/assets/xychartDiagram-e933f94c-7rTYP6vy.js +7 -0
- package/dist-renderer/assets/zh-CN-LNUGB5OW-DDjjE3j0.js +10 -0
- package/dist-renderer/assets/zh-HK-E62DVLB3-CUaw1jmU.js +1 -0
- package/dist-renderer/assets/zh-TW-RAJ6MFWO-BFOuD9P0.js +9 -0
- package/dist-renderer/index.html +13 -0
- package/package.json +8 -4
- package/skills/council-install/SKILL.md +63 -0
- package/skills/council-manage/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,124 +1,143 @@
|
|
|
1
1
|
# @statechange/council
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build a council of AI personas and have them debate any topic. Each counsellor has their own LLM backend, model, personality, and source material. Run discussions in a structured **debate** format or an open **freeform** group chat — via the CLI, an Electron GUI, or Claude Code skills.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Getting Started with Claude Code Skills
|
|
6
6
|
|
|
7
|
-
The fastest
|
|
7
|
+
The fastest path is to add the skills to [Claude Code](https://claude.com/claude-code). They handle installation, configuration, counsellor creation, and running discussions for you.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
npx skills add statechangelabs/ai-council
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This gives you two skills:
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
| Skill | What it does |
|
|
16
|
+
|-------|-------------|
|
|
17
|
+
| `/council-manage` | Create counsellors, run discussions, manage your council. Try: *"create a counsellor based on Warren Buffett"* or *"run a debate about whether AI should be open source"* |
|
|
18
|
+
| `/council-setup-keys` | Finds API keys scattered across your env files and shell profiles, then imports them into `~/.ai-council/config.json` |
|
|
17
19
|
|
|
18
|
-
The skills
|
|
20
|
+
The skills will install the `council` CLI automatically if it's not already on your system.
|
|
19
21
|
|
|
20
22
|
## Install
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
|
-
# Global install (
|
|
25
|
+
# Global install (gives you the `council` command)
|
|
24
26
|
npm install -g @statechange/council
|
|
25
27
|
|
|
26
|
-
# Or run
|
|
28
|
+
# Or run one-off without installing
|
|
27
29
|
npx @statechange/council discuss "Should we adopt microservices?"
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
## CLI
|
|
32
|
+
## CLI
|
|
33
|
+
|
|
34
|
+
### Run a discussion
|
|
31
35
|
|
|
32
36
|
```bash
|
|
33
|
-
#
|
|
37
|
+
# Freeform (default) — open group chat, everyone sees everything
|
|
34
38
|
council discuss "Should we pivot to enterprise?" --rounds 3
|
|
35
39
|
|
|
36
|
-
#
|
|
40
|
+
# Debate — structured constructive/rebuttal format
|
|
37
41
|
council discuss "Should AI be open source?" --mode debate --rounds 3
|
|
38
42
|
|
|
39
|
-
#
|
|
43
|
+
# Pick specific counsellors
|
|
40
44
|
council discuss "Topic" --counsellors ./council/strategist ./council/critic
|
|
41
45
|
|
|
42
46
|
# Topic from a file
|
|
43
47
|
council discuss ./topics/architecture.md
|
|
48
|
+
```
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
council list
|
|
50
|
+
### Manage counsellors
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
council
|
|
50
|
-
council
|
|
52
|
+
```bash
|
|
53
|
+
council list # Show available counsellors
|
|
54
|
+
council counsellor add ./path/to/counsellor # Register from local directory
|
|
55
|
+
council counsellor add https://github.com/user/counsellors.git # From git
|
|
56
|
+
council counsellor remove my-counsellor # Unregister
|
|
51
57
|
```
|
|
52
58
|
|
|
53
|
-
###
|
|
59
|
+
### View history
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
council history # List past discussions
|
|
63
|
+
council history <id> # View a specific discussion
|
|
64
|
+
```
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
### Configure backends
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
```bash
|
|
69
|
+
council config show # See what's configured
|
|
70
|
+
council config scan # Find API keys across your system
|
|
71
|
+
council config scan ~/project/.env # Scan additional paths
|
|
72
|
+
council config import # Import discovered keys into config
|
|
73
|
+
```
|
|
61
74
|
|
|
62
|
-
###
|
|
75
|
+
### All CLI options
|
|
63
76
|
|
|
64
77
|
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
--
|
|
68
|
-
--
|
|
69
|
-
--
|
|
70
|
-
--
|
|
71
|
-
--
|
|
78
|
+
council discuss <topic> [options]
|
|
79
|
+
|
|
80
|
+
--mode, -m freeform or debate (default: freeform)
|
|
81
|
+
--rounds, -r Number of discussion rounds (default: 2)
|
|
82
|
+
--council, -c Path to council directory (default: ./council/)
|
|
83
|
+
--counsellors Specific counsellor directory paths (space-separated)
|
|
84
|
+
--output, -o Output directory (default: ./output)
|
|
85
|
+
--format, -f md, json, or both (default: both)
|
|
86
|
+
--infographic, -i Generate an infographic after discussion
|
|
72
87
|
```
|
|
73
88
|
|
|
74
89
|
## GUI
|
|
75
90
|
|
|
76
|
-
|
|
91
|
+
The Electron app gives you a visual interface with real-time streaming, point-and-click counsellor management, and full discussion history.
|
|
77
92
|
|
|
78
93
|
```bash
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
# From the cloned repo
|
|
95
|
+
git clone https://github.com/statechangelabs/ai-council.git
|
|
96
|
+
cd ai-council
|
|
97
|
+
bun install
|
|
82
98
|
bun run dev:gui
|
|
83
99
|
```
|
|
84
100
|
|
|
85
|
-
|
|
86
|
-
- Counsellor selection chips with health indicators
|
|
87
|
-
- Freeform/Debate mode toggle with explanatory tooltips
|
|
88
|
-
- Real-time streaming of counsellor responses
|
|
89
|
-
- Round dividers and interim summaries in debate mode
|
|
90
|
-
- Secretary summary with Excalidraw position diagrams
|
|
91
|
-
- Infographic generation (OpenAI / Google)
|
|
92
|
-
- Full discussion history with search
|
|
101
|
+
### What you get
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
- **Discussion page** — Topic input with file attachments, counsellor selection chips, freeform/debate mode toggle, real-time streaming of responses, round dividers and interim summaries in debate mode, inject messages mid-discussion
|
|
104
|
+
- **Counsellors page** — Browse, search, create, edit, and delete counsellors with a form editor or raw ABOUT.md editing; register external counsellors from local paths or git repos
|
|
105
|
+
- **History page** — Browse past discussions, view full transcripts with round summaries, copy as markdown, generate infographics
|
|
106
|
+
- **Settings page** — Configure API keys per backend, test connections, see available models
|
|
95
107
|
|
|
96
|
-
|
|
108
|
+
## Discussion Modes
|
|
97
109
|
|
|
98
|
-
|
|
110
|
+
### Freeform
|
|
99
111
|
|
|
100
|
-
|
|
101
|
-
2. **Config file**: `~/.ai-council/config.json`
|
|
102
|
-
3. **`.env` file** in the project root
|
|
112
|
+
The default. An open group chat where every counsellor sees the full conversation history on every turn. The first speaker sets the tone and later speakers react to what's been said. Counsellor order stays the same each round.
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
### Debate
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
council config scan ~/project/.env # Scan additional paths
|
|
110
|
-
council config import # Import discovered keys
|
|
111
|
-
```
|
|
116
|
+
A structured argument format designed to prevent pile-on and anchoring bias:
|
|
117
|
+
|
|
118
|
+
1. **Round 1 — Constructive**: Each counsellor argues their position based *only* on the question. They can't see what anyone else said. Even a "critic" persona has to stand up their own argument first.
|
|
112
119
|
|
|
113
|
-
|
|
120
|
+
2. **Rebuttal rounds (2+)**: Counsellors now see the constructive round plus *only* the previous rebuttal round — not the entire history. This keeps context growth bounded. Speaker order is shuffled each round so nobody is always first or last.
|
|
121
|
+
|
|
122
|
+
3. **Interim summaries**: If a secretary is configured, a brief summary is generated after every round, tracking emerging agreements, disagreements, and shifts in position.
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
### API Keys
|
|
127
|
+
|
|
128
|
+
Each backend needs an API key (except Ollama, which runs locally). Keys are resolved in order:
|
|
129
|
+
|
|
130
|
+
1. `~/.ai-council/config.json` (managed by `council config import` or the GUI)
|
|
131
|
+
2. Environment variables: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`
|
|
132
|
+
3. `.env` file in the working directory
|
|
114
133
|
|
|
115
134
|
### Secretary
|
|
116
135
|
|
|
117
|
-
|
|
136
|
+
Enable post-discussion summaries (and debate interim summaries) by adding a `secretary` block to `~/.ai-council/config.json`:
|
|
118
137
|
|
|
119
138
|
```json
|
|
120
139
|
{
|
|
121
|
-
"backends": { ... },
|
|
140
|
+
"backends": { "..." : "..." },
|
|
122
141
|
"secretary": {
|
|
123
142
|
"backend": "anthropic",
|
|
124
143
|
"model": "claude-sonnet-4-5-20250929"
|
|
@@ -126,9 +145,18 @@ Add a `secretary` block to `~/.ai-council/config.json` to enable post-discussion
|
|
|
126
145
|
}
|
|
127
146
|
```
|
|
128
147
|
|
|
148
|
+
### Supported Backends
|
|
149
|
+
|
|
150
|
+
| Backend | Default Model | API Key |
|
|
151
|
+
|---------|--------------|---------|
|
|
152
|
+
| anthropic | claude-sonnet-4-5-20250929 | `ANTHROPIC_API_KEY` |
|
|
153
|
+
| openai | gpt-4o | `OPENAI_API_KEY` |
|
|
154
|
+
| google | gemini-2.0-flash | `GOOGLE_API_KEY` |
|
|
155
|
+
| ollama | llama3.2 | None (local) |
|
|
156
|
+
|
|
129
157
|
## Creating Counsellors
|
|
130
158
|
|
|
131
|
-
|
|
159
|
+
A counsellor is a directory containing an `ABOUT.md` file with YAML frontmatter and a system prompt:
|
|
132
160
|
|
|
133
161
|
```
|
|
134
162
|
council/
|
|
@@ -137,7 +165,7 @@ council/
|
|
|
137
165
|
avatar.jpg # optional
|
|
138
166
|
```
|
|
139
167
|
|
|
140
|
-
### ABOUT.md
|
|
168
|
+
### ABOUT.md format
|
|
141
169
|
|
|
142
170
|
```markdown
|
|
143
171
|
---
|
|
@@ -151,55 +179,58 @@ avatar: "avatar.jpg"
|
|
|
151
179
|
---
|
|
152
180
|
|
|
153
181
|
You are The Strategist. You sit on a council of experts and bring a
|
|
154
|
-
strategic lens to every discussion
|
|
182
|
+
strategic lens to every discussion.
|
|
183
|
+
|
|
184
|
+
When contributing:
|
|
185
|
+
- Think about second and third-order effects
|
|
186
|
+
- Consider offensive and defensive strategic positions
|
|
187
|
+
- Ground your thinking in frameworks when relevant
|
|
188
|
+
- Be direct and opinionated
|
|
189
|
+
|
|
190
|
+
Keep your responses focused. Aim for 2-4 paragraphs per turn.
|
|
155
191
|
```
|
|
156
192
|
|
|
157
|
-
###
|
|
193
|
+
### Frontmatter fields
|
|
158
194
|
|
|
159
|
-
|
|
|
160
|
-
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
|
|
|
195
|
+
| Field | Required | Description |
|
|
196
|
+
|-------|----------|-------------|
|
|
197
|
+
| `name` | Yes | Display name |
|
|
198
|
+
| `description` | Yes | One-line summary of this counsellor's perspective |
|
|
199
|
+
| `backend` | Yes | `anthropic`, `openai`, `google`, or `ollama` |
|
|
200
|
+
| `model` | No | Specific model ID; uses backend default if omitted |
|
|
201
|
+
| `temperature` | No | 0.0–2.0; higher = more creative (default varies by backend) |
|
|
202
|
+
| `interests` | No | Tags shown in the UI |
|
|
203
|
+
| `avatar` | No | Path to local image or URL |
|
|
165
204
|
|
|
166
|
-
###
|
|
205
|
+
### Included counsellors
|
|
167
206
|
|
|
168
|
-
|
|
169
|
-
# From a local directory
|
|
170
|
-
council counsellor add ./path/to/counsellor
|
|
207
|
+
The package ships with three starter counsellors:
|
|
171
208
|
|
|
172
|
-
|
|
173
|
-
|
|
209
|
+
| Counsellor | Backend | Perspective |
|
|
210
|
+
|-----------|---------|-------------|
|
|
211
|
+
| **The Strategist** | Anthropic (Haiku) | Strategic business advisor — positioning, growth, competitive advantage |
|
|
212
|
+
| **The Creative** | Anthropic (Opus) | Lateral thinker — unexpected analogies, reframing, unconventional connections |
|
|
213
|
+
| **The Critic** | Google (Gemini Flash) | Devil's advocate — stress-tests ideas, surfaces assumptions, finds failure modes |
|
|
174
214
|
|
|
175
|
-
|
|
176
|
-
council counsellor list
|
|
215
|
+
### Building counsellors from source material
|
|
177
216
|
|
|
178
|
-
|
|
179
|
-
council counsellor remove my-counsellor
|
|
180
|
-
```
|
|
217
|
+
You can create counsellors based on real people or bodies of work by appending reference material below the system prompt. The `/council-manage` skill in Claude Code can automate this — ask it to *"create a counsellor based on [person or book]"* and it'll handle downloading source text, writing the system prompt, and assembling the ABOUT.md.
|
|
181
218
|
|
|
182
219
|
## Logging
|
|
183
220
|
|
|
184
|
-
Errors are logged to `~/.ai-council/council.log` with timestamps, context, and full stack traces. Check this file when a counsellor fails to respond or a summary doesn't generate.
|
|
221
|
+
Errors are logged to `~/.ai-council/council.log` with timestamps, context tags, and full stack traces. Check this file when a counsellor fails to respond or a summary doesn't generate.
|
|
185
222
|
|
|
186
223
|
## Development
|
|
187
224
|
|
|
188
225
|
```bash
|
|
189
|
-
|
|
226
|
+
git clone https://github.com/statechangelabs/ai-council.git
|
|
227
|
+
cd ai-council
|
|
190
228
|
bun install
|
|
191
229
|
|
|
192
|
-
# CLI development
|
|
193
|
-
bun run dev
|
|
194
|
-
|
|
195
|
-
# GUI
|
|
196
|
-
bun run dev:gui
|
|
197
|
-
|
|
198
|
-
# Build CLI
|
|
199
|
-
bun run build
|
|
200
|
-
|
|
201
|
-
# Build GUI
|
|
202
|
-
bun run build:gui
|
|
230
|
+
bun run dev -- discuss "topic" # CLI development
|
|
231
|
+
bun run dev:gui # GUI development
|
|
232
|
+
bun run build # Build CLI
|
|
233
|
+
bun run build:gui # Build GUI
|
|
203
234
|
```
|
|
204
235
|
|
|
205
236
|
## License
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,8 @@ import { ListCommand } from "./commands/list.js";
|
|
|
9
9
|
import { ConfigCommand } from "./commands/config.js";
|
|
10
10
|
import { CounsellorCommand } from "./commands/counsellor.js";
|
|
11
11
|
import { HistoryCommand } from "./commands/history.js";
|
|
12
|
+
import { GuiCommand } from "./commands/gui.js";
|
|
13
|
+
import { InstallCommand } from "./commands/install.js";
|
|
12
14
|
const cli = meow(`
|
|
13
15
|
Usage
|
|
14
16
|
$ council <command> [options]
|
|
@@ -21,6 +23,9 @@ const cli = meow(`
|
|
|
21
23
|
counsellor add <path-or-url> Register a counsellor from a local path or git URL
|
|
22
24
|
counsellor remove <id> Unregister a counsellor (--yes to delete cloned files)
|
|
23
25
|
counsellor list List all registered counsellors
|
|
26
|
+
gui Launch the Electron GUI
|
|
27
|
+
install Install AI Council as a macOS application
|
|
28
|
+
install --uninstall Remove AI Council from Applications
|
|
24
29
|
config show Show current configuration and key status
|
|
25
30
|
config scan [paths..] Scan for API keys in env files and shell profiles
|
|
26
31
|
config import [paths..] Import discovered keys into ~/.ai-council/config.json
|
|
@@ -93,6 +98,10 @@ const cli = meow(`
|
|
|
93
98
|
shortFlag: "y",
|
|
94
99
|
default: false,
|
|
95
100
|
},
|
|
101
|
+
uninstall: {
|
|
102
|
+
type: "boolean",
|
|
103
|
+
default: false,
|
|
104
|
+
},
|
|
96
105
|
},
|
|
97
106
|
});
|
|
98
107
|
const command = cli.input[0];
|
|
@@ -136,6 +145,12 @@ switch (command) {
|
|
|
136
145
|
render(_jsx(CounsellorCommand, { subcommand: sub, target: target, yes: cli.flags.yes }));
|
|
137
146
|
break;
|
|
138
147
|
}
|
|
148
|
+
case "gui":
|
|
149
|
+
render(_jsx(GuiCommand, {}));
|
|
150
|
+
break;
|
|
151
|
+
case "install":
|
|
152
|
+
render(_jsx(InstallCommand, { uninstall: cli.flags.uninstall }));
|
|
153
|
+
break;
|
|
139
154
|
case "config": {
|
|
140
155
|
const sub = cli.input[1];
|
|
141
156
|
if (!sub || !["show", "scan", "import"].includes(sub)) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";;AAEA,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,GAAG,GAAG,IAAI,CACd
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function GuiCommand(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Text } from "ink";
|
|
4
|
+
import { spawn, execSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { resolve, dirname } from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
export function GuiCommand() {
|
|
9
|
+
const [status, setStatus] = useState("Locating Electron...");
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
async function launch() {
|
|
13
|
+
// Resolve dist-electron/main.js relative to this package
|
|
14
|
+
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
15
|
+
const mainJs = resolve(pkgRoot, "dist-electron/main.js");
|
|
16
|
+
if (!existsSync(mainJs)) {
|
|
17
|
+
setError(`Could not find Electron entry point at ${mainJs}\n` +
|
|
18
|
+
"Make sure the GUI has been built: bun run build:gui");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// Try to find the electron binary
|
|
22
|
+
let electronPath = null;
|
|
23
|
+
// Method 1: require.resolve("electron") — the npm package exports the binary path
|
|
24
|
+
try {
|
|
25
|
+
const { createRequire } = await import("node:module");
|
|
26
|
+
const require = createRequire(import.meta.url);
|
|
27
|
+
electronPath = require("electron");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// not installed locally
|
|
31
|
+
}
|
|
32
|
+
// Method 2: check PATH
|
|
33
|
+
if (!electronPath) {
|
|
34
|
+
try {
|
|
35
|
+
electronPath = execSync("which electron", { encoding: "utf-8" }).trim();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// not in PATH
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!electronPath) {
|
|
42
|
+
setError("The GUI requires Electron. Install it with:\n\n" +
|
|
43
|
+
" npm install -g electron\n");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Spawn electron as a detached process so the CLI can exit
|
|
47
|
+
setStatus("Launching AI Council GUI...");
|
|
48
|
+
const child = spawn(electronPath, [mainJs], {
|
|
49
|
+
detached: true,
|
|
50
|
+
stdio: "ignore",
|
|
51
|
+
});
|
|
52
|
+
child.unref();
|
|
53
|
+
// Give it a moment then exit
|
|
54
|
+
setTimeout(() => process.exit(0), 500);
|
|
55
|
+
}
|
|
56
|
+
launch();
|
|
57
|
+
}, []);
|
|
58
|
+
if (error) {
|
|
59
|
+
return _jsx(Text, { color: "red", children: error });
|
|
60
|
+
}
|
|
61
|
+
return _jsx(Text, { children: status });
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=gui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui.js","sourceRoot":"","sources":["../../src/commands/gui.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,UAAU,UAAU;IACxB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAS,sBAAsB,CAAC,CAAC;IACrE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,UAAU,MAAM;YACnB,yDAAyD;YACzD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAEzD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxB,QAAQ,CACN,0CAA0C,MAAM,IAAI;oBAClD,qDAAqD,CACxD,CAAC;gBACF,OAAO;YACT,CAAC;YAED,kCAAkC;YAClC,IAAI,YAAY,GAAkB,IAAI,CAAC;YAEvC,kFAAkF;YAClF,IAAI,CAAC;gBACH,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;gBACtD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC/C,YAAY,GAAG,OAAO,CAAC,UAAU,CAAsB,CAAC;YAC1D,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;YAED,uBAAuB;YACvB,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,IAAI,CAAC;oBACH,YAAY,GAAG,QAAQ,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC1E,CAAC;gBAAC,MAAM,CAAC;oBACP,cAAc;gBAChB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,QAAQ,CACN,iDAAiD;oBAC/C,6BAA6B,CAChC,CAAC;gBACF,OAAO;YACT,CAAC;YAED,2DAA2D;YAC3D,SAAS,CAAC,6BAA6B,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,EAAE;gBAC1C,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC;YACH,KAAK,CAAC,KAAK,EAAE,CAAC;YAEd,6BAA6B;YAC7B,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,EAAE,CAAC;IACX,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,KAAK,GAAQ,CAAC;IAC1C,CAAC;IAED,OAAO,KAAC,IAAI,cAAE,MAAM,GAAQ,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Text } from "ink";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { resolve, dirname } from "node:path";
|
|
7
|
+
import { existsSync, mkdirSync, writeFileSync, chmodSync, rmSync } from "node:fs";
|
|
8
|
+
const APP_PATH = "/Applications/AI Council.app";
|
|
9
|
+
export function InstallCommand({ uninstall }) {
|
|
10
|
+
const [status, setStatus] = useState(uninstall ? "Removing AI Council..." : "Installing AI Council...");
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (uninstall) {
|
|
14
|
+
if (!existsSync(APP_PATH)) {
|
|
15
|
+
setStatus("AI Council is not installed in /Applications.");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
rmSync(APP_PATH, { recursive: true, force: true });
|
|
20
|
+
setStatus("AI Council removed from /Applications.");
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
setError(`Failed to remove ${APP_PATH}: ${err.message}`);
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
async function install() {
|
|
28
|
+
// Install flow
|
|
29
|
+
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
30
|
+
const mainJs = resolve(pkgRoot, "dist-electron/main.js");
|
|
31
|
+
if (!existsSync(mainJs)) {
|
|
32
|
+
setError(`Could not find Electron entry point at ${mainJs}\n` +
|
|
33
|
+
"Make sure the GUI has been built: bun run build:gui");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Verify electron is available
|
|
37
|
+
let electronPath = null;
|
|
38
|
+
try {
|
|
39
|
+
const { createRequire } = await import("node:module");
|
|
40
|
+
const req = createRequire(import.meta.url);
|
|
41
|
+
electronPath = req("electron");
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// not installed locally
|
|
45
|
+
}
|
|
46
|
+
if (!electronPath) {
|
|
47
|
+
try {
|
|
48
|
+
electronPath = execSync("which electron", { encoding: "utf-8" }).trim();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// not in PATH
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!electronPath) {
|
|
55
|
+
setError("The GUI requires Electron. Install it with:\n\n" +
|
|
56
|
+
" npm install -g electron\n");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Build the .app structure
|
|
60
|
+
const contentsDir = resolve(APP_PATH, "Contents");
|
|
61
|
+
const macosDir = resolve(contentsDir, "MacOS");
|
|
62
|
+
const resourcesDir = resolve(contentsDir, "Resources");
|
|
63
|
+
try {
|
|
64
|
+
mkdirSync(macosDir, { recursive: true });
|
|
65
|
+
mkdirSync(resourcesDir, { recursive: true });
|
|
66
|
+
// Info.plist
|
|
67
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
68
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
69
|
+
<plist version="1.0">
|
|
70
|
+
<dict>
|
|
71
|
+
<key>CFBundleName</key>
|
|
72
|
+
<string>AI Council</string>
|
|
73
|
+
<key>CFBundleDisplayName</key>
|
|
74
|
+
<string>AI Council</string>
|
|
75
|
+
<key>CFBundleIdentifier</key>
|
|
76
|
+
<string>com.statechange.council</string>
|
|
77
|
+
<key>CFBundleVersion</key>
|
|
78
|
+
<string>1.0</string>
|
|
79
|
+
<key>CFBundlePackageType</key>
|
|
80
|
+
<string>APPL</string>
|
|
81
|
+
<key>CFBundleExecutable</key>
|
|
82
|
+
<string>ai-council</string>
|
|
83
|
+
</dict>
|
|
84
|
+
</plist>`;
|
|
85
|
+
writeFileSync(resolve(contentsDir, "Info.plist"), plist);
|
|
86
|
+
// Launcher shell script
|
|
87
|
+
const launcher = `#!/bin/bash
|
|
88
|
+
MAIN_JS="${mainJs}"
|
|
89
|
+
|
|
90
|
+
# Find electron binary
|
|
91
|
+
ELECTRON=""
|
|
92
|
+
|
|
93
|
+
# Method 1: npm global modules
|
|
94
|
+
if [ -z "$ELECTRON" ]; then
|
|
95
|
+
NPM_ROOT=$(npm root -g 2>/dev/null)
|
|
96
|
+
if [ -n "$NPM_ROOT" ] && [ -f "$NPM_ROOT/electron/dist/Electron.app/Contents/MacOS/Electron" ]; then
|
|
97
|
+
ELECTRON="$NPM_ROOT/electron/dist/Electron.app/Contents/MacOS/Electron"
|
|
98
|
+
elif [ -n "$NPM_ROOT" ] && [ -f "$NPM_ROOT/electron/cli.js" ]; then
|
|
99
|
+
ELECTRON=$(node "$NPM_ROOT/electron/cli.js" --print-path 2>/dev/null || echo "")
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Method 2: PATH
|
|
104
|
+
if [ -z "$ELECTRON" ]; then
|
|
105
|
+
ELECTRON=$(which electron 2>/dev/null || echo "")
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [ -z "$ELECTRON" ]; then
|
|
109
|
+
osascript -e 'display alert "Electron not found" message "Install Electron with: npm install -g electron" as critical'
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
exec "$ELECTRON" "$MAIN_JS"
|
|
114
|
+
`;
|
|
115
|
+
const launcherPath = resolve(macosDir, "ai-council");
|
|
116
|
+
writeFileSync(launcherPath, launcher);
|
|
117
|
+
chmodSync(launcherPath, 0o755);
|
|
118
|
+
setStatus("AI Council installed to /Applications.\nYou can find it in Spotlight or Launchpad.");
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
setError(`Failed to create ${APP_PATH}: ${err.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
install();
|
|
125
|
+
}, []);
|
|
126
|
+
if (error) {
|
|
127
|
+
return _jsx(Text, { color: "red", children: error });
|
|
128
|
+
}
|
|
129
|
+
return _jsx(Text, { color: "green", children: status });
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.tsx"],"names":[],"mappings":"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"}
|