You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Programmatic callers (like /discuss) no longer surface per-expert prompts to the user. Adds 'interactive' parameter (default false) to the recruiting protocol: fresh-install users running /discuss now see one intake Q-round + one roster confirmation instead of N prompts asking about individual experts.
Cache behavior: silent on all failure modes. Unwritable data root, missing directory, or WITS_CACHE=off never block or surface to the user — personas are still returned, just not persisted. Adds WITS_CACHE=off escape hatch for users who want fully stateless runs.
discuss: pinned recruit callsites in Step 4 (domain coverage), Step 5 (facilitator panel review), and the mid-discussion recruit_expert handler to interactive=false. The Step 6 roster-confirmation prompt is now marked as the single user-facing approval surface for expert selection.
Copy file name to clipboardExpand all lines: references/data-root.md
+10-7Lines changed: 10 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,10 @@ Skills in this plugin that persist data (recruit, discuss) use a shared data roo
4
4
5
5
## Resolution Order
6
6
7
-
1.**Environment variable**: `WITS_DATA_DIR` — if set, use this path
8
-
2.**XDG default**: `~/.local/share/wits/`
9
-
3.**Ephemeral fallback**: `/tmp/wits-$USER/` — used when home directory is not writable
7
+
1.**Disable caching entirely**: if `WITS_CACHE=off`, skip all reads/writes (skills run stateless — personas are generated fresh each time)
8
+
2.**Environment variable**: `WITS_DATA_DIR` — if set, use this path
9
+
3.**XDG default**: `~/.local/share/wits/`
10
+
4.**Ephemeral fallback**: `/tmp/wits-$USER/` — used when home directory is not writable
10
11
11
12
## Directory Structure
12
13
@@ -21,10 +22,12 @@ Skills in this plugin that persist data (recruit, discuss) use a shared data roo
21
22
22
23
When a skill needs to read or write persistent data:
23
24
24
-
1. Check if `WITS_DATA_DIR` is set: `echo $WITS_DATA_DIR`
25
-
2. If not set, use `~/.local/share/wits/`
26
-
3. Create subdirectories on first use (don't assume they exist)
27
-
4. If directory creation fails (permissions), fall back to `/tmp/wits-$USER/` and warn the user
25
+
1. Check if `WITS_CACHE=off` — if so, skip all persistence and run stateless
26
+
2. Check if `WITS_DATA_DIR` is set: `echo $WITS_DATA_DIR`
27
+
3. If not set, use `~/.local/share/wits/`
28
+
4. Create subdirectories on first use (don't assume they exist)
29
+
5. If directory creation fails (permissions), fall back to `/tmp/wits-$USER/` silently. Do not prompt or warn the user — caching is a silent optimization and skills must work the same whether the cache succeeds or not.
30
+
6. If even `/tmp` fails, run stateless (reads return empty, writes are no-ops). Never block on cache failures.
Copy file name to clipboardExpand all lines: skills/discuss/SKILL.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,7 +60,7 @@ If the intake agent returns questions, present them to the user. After answers (
60
60
61
61
2.**Domain coverage** — identify needed voices by domain:
62
62
- From the intake agent's topic brief, extract domain areas
63
-
- For each domain, call `/recruit` (search → evaluate → offer → reuse/create) to get a primary expert
63
+
- For each domain, call `/recruit`with `interactive=false`(search → evaluate → decide silently → reuse-or-create) to get a primary expert. Recruit does not prompt the user during this phase — the roster-confirmation step below is the single user-facing approval surface for the whole recruiting pass.
64
64
- Number based on `--size` flag or auto-heuristic (1-2 domains → 1-2 experts, 3-4 → 2-3, 5+ → 3-4+)
@@ -83,12 +83,13 @@ If the intake agent returns questions, present them to the user. After answers (
83
83
5.**Facilitator panel review**[NEW]:
84
84
- Before locking the roster, dispatch the facilitator ONCE with the proposed panel + topic brief.
85
85
- Prompt: "Here's the proposed panel: [list]. Topic: [brief]. Critique it: what stance is missing? Who would disagree with the emerging frame for reasons none of these people would voice? Answer in 3-5 sentences. If the panel is adequate, say 'adequate' and why."
86
-
- If facilitator flags a gap: recruit one more expert to fill it (call `/recruit create` with the gap description) before proceeding. Max one additional recruit from this step — if the facilitator keeps flagging gaps after that, proceed anyway and note the limitation in the final report.
86
+
- If facilitator flags a gap: recruit one more expert to fill it by calling `/recruit create` with `interactive=false` and the gap description. Max one additional recruit from this step — if the facilitator keeps flagging gaps after that, proceed anyway and note the limitation in the final report. Still no user prompt at this stage.
87
87
88
-
6. Present the assembled roster to the user: "Your discussion team: [names + roles + stances + models]"
88
+
6.**Present the assembled roster to the user — the single approval surface:** "Your discussion team: [names + roles + stances + models]"
89
89
- Show the stance distribution explicitly
90
90
- User can say "add <domain>" or "remove <name>" to customize
91
91
- Once confirmed, write `team.json` to `tmp/discuss-<session-id>/`
92
+
- This is the ONLY user-facing prompt for expert selection. All per-expert decisions (reuse vs create, name, persona details) happen silently inside `/recruit` during steps 2–5. A fresh-install user with no cached experts should see exactly one intake question round plus this one roster confirmation — not N prompts about individual experts.
Copy file name to clipboardExpand all lines: skills/discuss/references/orchestration.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -423,10 +423,11 @@ Invoked when the facilitator names a structural voice gap — usually in respons
423
423
424
424
**Steps:**
425
425
426
-
1.**Invoke `/recruit create`** with the `domain` field from the action. Pass the `rationale` as additional context so the recruit skill can evaluate reuse of existing experts. Recruit follows its normal search → evaluate → offer → reuse/create flow and returns:
426
+
1.**Invoke `/recruit create`** with `interactive=false`, the `domain` field from the action, and the `rationale` as additional context. Recruit silently runs its search → evaluate → decide → reuse-or-create flow (no user prompt inside recruit) and returns:
Copy file name to clipboardExpand all lines: skills/recruit/SKILL.md
+27-7Lines changed: 27 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,6 +43,10 @@ Create a new expert persona and add it to the registry.
43
43
44
44
Other skills call this protocol during their setup phases. Follow these steps in order.
45
45
46
+
**Default mode is non-interactive.** Programmatic callers (like `/discuss`) do NOT surface per-expert prompts to the user — the recruiting phase runs silently and returns the assembled personas. The calling skill is responsible for presenting the final roster to the user once, at its own approval surface. This is the contract: recruit is infrastructure, not a user-facing dialog.
47
+
48
+
Callers can request interactive mode by passing `interactive=true` (e.g. a debugging flow where the user wants to review each pick). Default: `false`.
49
+
46
50
### Step 1: Search
47
51
48
52
```
@@ -55,16 +59,26 @@ Scan for matching tags and domains. If the INDEX has no hits, also try:
55
59
rg -i "<domain_keyword>" <data-root>/experts/*.md
56
60
```
57
61
62
+
If the data root doesn't exist or isn't readable, treat as "no matches" and proceed to Step 5 (Create). Do not prompt.
63
+
58
64
### Step 2: Evaluate
59
65
60
66
For each candidate match, assess fit:
61
67
-**Domain alignment**: Does the expert's domain cover what's needed? Partial overlap is OK if the core area matches.
62
68
-**Research freshness**: If the expert's Research Context includes specific version-pinned or date-sensitive information, check if it's still accurate (>1 year → flag for refresh).
63
69
-**Thinking style fit**: Does the persona's thinking style match the task? A "risk-averse systems thinker" is the right choice for a migration review but may be too conservative for a brainstorming session.
64
70
65
-
### Step 3: Offer
71
+
Score each candidate on the three axes. A match is "strong" if domain alignment is clearly present AND research is fresh AND thinking style fits the task context.
72
+
73
+
### Step 3: Decide (silent in programmatic mode)
66
74
67
-
Present matches to the caller (or user, if user-invoked):
> "Found cached expert **Dr. PostgreSQL** (database, postgresql, migration — last used 3 days ago). Reuse, or create a fresh expert for this domain?"
70
84
@@ -75,22 +89,24 @@ If no match: skip to Step 5.
75
89
When reusing a cached expert:
76
90
1. Load the full file from `<data-root>/experts/<slug>.md`
77
91
2. Extract the Persona Prompt and Research Context sections
78
-
3. Update `last_used` to today's date in the file frontmatter
92
+
3. Update `last_used` to today's date in the file frontmatter (best-effort — skip silently if the data root isn't writable)
79
93
4. Add the calling skill to `consumers[]` if not already present
80
94
5. Return the persona text to the caller
81
95
82
-
### Step 5: Create (when no suitable match exists)
96
+
### Step 5: Create (when no suitable match exists or data root is empty/unavailable)
83
97
84
98
1.**Identify the domain**: Narrow and specific beats broad. "PostgreSQL migration specialist" beats "database expert."
85
99
2.**Build persona** using `references/expert-template.md`:
86
100
- Choose a name that creates a character (not "Expert #1")
87
101
- Define thinking style, key frameworks, what they look for, blind spots
88
102
- Write the Persona Prompt (100-300 words, second person: "You are...")
89
103
3.**Deep research** (if triggered — see criteria below): dispatch a research subagent, save findings under `## Research Context`
90
-
4.**Save**: write to `<data-root>/experts/<slug>.md`
91
-
5.**Update INDEX.md**: add a row to the Domain Experts table with name, domain, tags, last used, created date
104
+
4.**Save**: write to `<data-root>/experts/<slug>.md` if the data root is writable. If not writable, skip the write silently — the persona is still returned to the caller, it just isn't persisted for reuse.
105
+
5.**Update INDEX.md**: add a row to the Domain Experts table with name, domain, tags, last used, created date (best-effort — skip silently on write failure)
92
106
6. Return the persona text to the caller
93
107
108
+
Caching is an optimization. A failed or unavailable cache never blocks recruiting and never surfaces to the user in programmatic mode.
109
+
94
110
---
95
111
96
112
## Expert File Format
@@ -123,7 +139,10 @@ Expert data is stored under the **wits data root** (see `references/data-root.md
123
139
124
140
- Default: `~/.local/share/wits/experts/`
125
141
- Override: set `WITS_DATA_DIR` environment variable
126
-
- Fallback: `/tmp/wits-$USER/experts/` (ephemeral, with warning)
142
+
- Disable caching: set `WITS_CACHE=off` to skip all reads/writes (personas are generated fresh each time)
**Caching is a silent optimization.** If the data root is unwritable, missing, or caching is disabled, recruit proceeds without persisting — it never blocks, errors, or prompts the user about cache state. Reads return "no matches" on a missing/empty cache; writes are best-effort.
127
146
128
147
```
129
148
<data-root>/experts/
@@ -165,6 +184,7 @@ When calling the protocol programmatically, pass:
165
184
- The domain description (what expertise is needed)
166
185
- The task context (what the expert will be doing — affects thinking style selection)
167
186
- Whether deep research is acceptable (some callers are latency-sensitive)
187
+
-`interactive` (default `false`) — when `false`, recruit makes reuse-vs-create decisions silently and never prompts the user. The calling skill handles user-facing approval at its own layer (e.g. `/discuss` shows the assembled panel once, after all recruitment is done). Set `true` only when the caller genuinely wants per-expert user review.
0 commit comments