dual-brain 4.6.0 → 4.7.1

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/orchestrator.json CHANGED
@@ -3,87 +3,66 @@
3
3
  "claude": {
4
4
  "plan": "$100",
5
5
  "models": {
6
- "opus": {
7
- "tier": "think",
8
- "input_per_mtok": 5.0,
9
- "output_per_mtok": 25.0,
10
- "context_window": 1000000,
11
- "max_output": 128000,
12
- "model_id": "claude-opus-4-6",
13
- "strengths": ["agentic coding", "complex reasoning", "tool use", "error recovery", "architecture decisions"],
14
- "weaknesses": ["higher latency", "tokenizer tax on 4.7 (12-35% more tokens)"],
15
- "best_for": "architecture, security review, complex debugging, multi-step planning",
16
- "avoid_for": "simple file reads, grep, formatting — wasteful at this tier"
17
- },
18
- "sonnet": {
19
- "tier": "execute",
20
- "input_per_mtok": 3.0,
21
- "output_per_mtok": 15.0,
22
- "context_window": 1000000,
23
- "max_output": 64000,
24
- "model_id": "claude-sonnet-4-6",
25
- "strengths": ["best speed/intelligence ratio", "precise minimal diffs", "1M context", "extended thinking"],
26
- "weaknesses": ["less reliable on complex multi-step reasoning than Opus"],
27
- "best_for": "implementation, refactoring, test writing, code edits, git operations",
28
- "avoid_for": "architecture decisions, security audits — upgrade to think tier"
29
- },
30
- "haiku": {
31
- "tier": "search",
32
- "input_per_mtok": 1.0,
33
- "output_per_mtok": 5.0,
34
- "context_window": 200000,
35
- "max_output": 64000,
36
- "model_id": "claude-haiku-4-5-20251001",
37
- "strengths": ["fastest latency", "cheapest", "good enough for read-only tasks"],
38
- "weaknesses": ["200k context (vs 1M for others)", "weaker reasoning", "older knowledge cutoff"],
39
- "best_for": "file lookups, grep, explore, read-only research, listing files",
40
- "avoid_for": "any task requiring edits, reasoning, or judgment"
41
- }
6
+ "opus": { "tier": "think", "input_per_mtok": 5.0, "output_per_mtok": 25.0, "context_window": 1000000, "max_output": 128000 },
7
+ "sonnet": { "tier": "execute", "input_per_mtok": 3.0, "output_per_mtok": 15.0, "context_window": 1000000, "max_output": 64000 },
8
+ "haiku": { "tier": "search", "input_per_mtok": 1.0, "output_per_mtok": 5.0, "context_window": 200000, "max_output": 64000 }
42
9
  }
43
10
  },
44
11
  "openai": {
45
12
  "plan": "$100",
46
13
  "models": {
47
- "gpt-5.5": {
48
- "tier": "think",
49
- "input_per_mtok": 5.0,
50
- "output_per_mtok": 30.0,
51
- "context_window": 1000000,
52
- "max_output": 128000,
53
- "model_id": "gpt-5.5",
54
- "strengths": ["complex reasoning", "fast interactive responses", "strong code review", "independent perspective from Claude"],
55
- "weaknesses": ["different failure modes than Claude — feature not bug for dual-brain"],
56
- "best_for": "independent code review (dual-brain), second opinions on architecture",
57
- "codex_compatible": true
58
- },
59
- "gpt-5.4": {
60
- "tier": "execute",
61
- "input_per_mtok": 2.5,
62
- "output_per_mtok": 15.0,
63
- "context_window": 1000000,
64
- "max_output": 128000,
65
- "model_id": "gpt-5.4",
66
- "strengths": ["good speed/cost ratio", "1M context", "strong instruction following"],
67
- "weaknesses": ["less capable reasoning than gpt-5.5"],
68
- "best_for": "implementation and execution tasks via Codex",
69
- "codex_compatible": true
70
- },
71
- "gpt-4.1-mini": {
72
- "tier": "search",
73
- "input_per_mtok": 0.40,
74
- "output_per_mtok": 1.60,
75
- "context_window": 1047576,
76
- "max_output": 32768,
77
- "model_id": "gpt-4.1-mini",
78
- "strengths": ["extremely cheap", "good instruction following", "1M context"],
79
- "weaknesses": ["32k max output", "no reasoning chain"],
80
- "best_for": "cheap search/lookup tasks via Codex",
81
- "codex_compatible": true
82
- }
14
+ "gpt-5.5": { "tier": "think", "input_per_mtok": 5.0, "output_per_mtok": 30.0, "context_window": 1000000, "max_output": 128000 },
15
+ "gpt-5.4": { "tier": "execute", "input_per_mtok": 2.5, "output_per_mtok": 15.0, "context_window": 1000000, "max_output": 128000 },
16
+ "gpt-4.1-mini": { "tier": "search", "input_per_mtok": 0.40, "output_per_mtok": 1.60, "context_window": 1047576, "max_output": 32768 }
83
17
  }
84
18
  }
85
19
  },
86
20
 
21
+ "model_intelligence": {
22
+ "opus": {
23
+ "model_id": "claude-opus-4-6",
24
+ "strengths": ["agentic coding", "complex reasoning", "tool use", "error recovery", "architecture decisions"],
25
+ "weaknesses": ["higher latency", "tokenizer tax on 4.7 (12-35% more tokens)"],
26
+ "best_for": "architecture, security review, complex debugging, multi-step planning",
27
+ "avoid_for": "simple file reads, grep, formatting — wasteful at this tier"
28
+ },
29
+ "sonnet": {
30
+ "model_id": "claude-sonnet-4-6",
31
+ "strengths": ["best speed/intelligence ratio", "precise minimal diffs", "1M context", "extended thinking"],
32
+ "weaknesses": ["less reliable on complex multi-step reasoning than Opus"],
33
+ "best_for": "implementation, refactoring, test writing, code edits, git operations",
34
+ "avoid_for": "architecture decisions, security audits — upgrade to think tier"
35
+ },
36
+ "haiku": {
37
+ "model_id": "claude-haiku-4-5-20251001",
38
+ "strengths": ["fastest latency", "cheapest", "good enough for read-only tasks"],
39
+ "weaknesses": ["200k context (vs 1M for others)", "weaker reasoning", "older knowledge cutoff"],
40
+ "best_for": "file lookups, grep, explore, read-only research, listing files",
41
+ "avoid_for": "any task requiring edits, reasoning, or judgment"
42
+ },
43
+ "gpt-5.5": {
44
+ "model_id": "gpt-5.5",
45
+ "strengths": ["complex reasoning", "fast interactive responses", "strong code review", "independent perspective from Claude"],
46
+ "weaknesses": ["different failure modes than Claude — feature not bug for dual-brain"],
47
+ "best_for": "independent code review (dual-brain), second opinions on architecture",
48
+ "codex_compatible": true
49
+ },
50
+ "gpt-5.4": {
51
+ "model_id": "gpt-5.4",
52
+ "strengths": ["good speed/cost ratio", "1M context", "strong instruction following"],
53
+ "weaknesses": ["less capable reasoning than gpt-5.5"],
54
+ "best_for": "implementation and execution tasks via Codex",
55
+ "codex_compatible": true
56
+ },
57
+ "gpt-4.1-mini": {
58
+ "model_id": "gpt-4.1-mini",
59
+ "strengths": ["extremely cheap", "good instruction following", "1M context"],
60
+ "weaknesses": ["32k max output", "no reasoning chain"],
61
+ "best_for": "cheap search/lookup tasks via Codex",
62
+ "codex_compatible": true
63
+ }
64
+ },
65
+
87
66
  "tiers": {
88
67
  "search": {
89
68
  "description": "Read-only lookups, exploration, grep, find, file reads",
@@ -121,6 +100,46 @@
121
100
  "model_routing_note": "Claude Code model: param may be silently ignored (issue #43869). Set CLAUDE_CODE_SUBAGENT_MODEL env var as fallback if subagents all run on parent model."
122
101
  },
123
102
 
103
+ "codex_skills": {
104
+ "review": {
105
+ "description": "Independent GPT code review via ChatGPT subscription",
106
+ "command": "node .claude/hooks/dual-brain-review.mjs",
107
+ "requires": "codex_auth"
108
+ },
109
+ "quality_gate": {
110
+ "description": "Config-driven quality gate with review artifacts",
111
+ "command": "node .claude/hooks/quality-gate.mjs"
112
+ },
113
+ "cost_report": {
114
+ "description": "Session activity and cost estimate by model tier",
115
+ "command": "node .claude/hooks/cost-report.mjs"
116
+ },
117
+ "test": {
118
+ "description": "Self-test harness for all orchestrator hooks",
119
+ "command": "node .claude/hooks/test-orchestrator.mjs"
120
+ },
121
+ "health_check": {
122
+ "description": "Verify all hooks are wired and system is healthy",
123
+ "command": "node .claude/hooks/health-check.mjs"
124
+ },
125
+ "session_report": {
126
+ "description": "Comprehensive session-end summary: activity by tier, routing compliance, quality gate status, data quality, drift warnings",
127
+ "command": "node .claude/hooks/session-report.mjs"
128
+ },
129
+ "setup_wizard": {
130
+ "description": "Interactive setup wizard — configures Claude Code hooks, dual-provider routing (Claude + OpenAI/Codex), subscription tiers, and cost-tracking settings",
131
+ "command": "node .claude/hooks/setup-wizard.mjs"
132
+ },
133
+ "gpt_dispatch": {
134
+ "description": "Dispatch execution tasks to GPT via Codex CLI",
135
+ "command": "node .claude/hooks/gpt-work-dispatcher.mjs"
136
+ },
137
+ "budget_balance": {
138
+ "description": "Show provider balance status and routing recommendations",
139
+ "command": "node .claude/hooks/budget-balancer.mjs"
140
+ }
141
+ },
142
+
124
143
  "pricing_verified": "2026-05-13",
125
144
 
126
145
  "budgets": {
@@ -134,7 +153,11 @@
134
153
  "routing": {
135
154
  "strategy": "hybrid-specialized-balanced",
136
155
  "codex_startup_penalty_ms": 20000,
137
- "min_codex_task_ms": 180000
156
+ "min_codex_task_ms": 180000,
157
+ "dual_thinking_permission_threshold": {
158
+ "estimated_tokens": 50000,
159
+ "agent_count": 2
160
+ }
138
161
  },
139
162
 
140
163
  "providers": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dual-brain",
3
- "version": "4.6.0",
4
- "description": "Data-Tools Dual-Brain — dual-provider orchestration extension for data-tools/replit-tools. Tiered routing, budget balancing, and GPT dual-brain review across Claude + OpenAI subscriptions",
3
+ "version": "4.7.1",
4
+ "description": "Dual-provider orchestration for Claude Code — tiered routing, budget balancing, and GPT dual-brain review across Claude + OpenAI subscriptions",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "dual-brain": "./install.mjs"
@@ -25,11 +25,6 @@
25
25
  "scripts": {
26
26
  "test": "node hooks/test-orchestrator.mjs"
27
27
  },
28
- "dataTools": {
29
- "extension": true,
30
- "requires": "replit-tools",
31
- "credit": "Built on data-tools by Steve Moraco"
32
- },
33
28
  "engines": {
34
29
  "node": ">=20.0.0"
35
30
  },
@@ -1,369 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * agent-chains.mjs — Opinionated multi-step agent workflows.
4
- *
5
- * Three built-in chains that map to how developers actually work:
6
- *
7
- * explore-then-fix — Understand the problem, then fix it
8
- * review-and-test — Review the code, then write tests for weak spots
9
- * audit-and-plan — Audit the architecture, then create an execution plan
10
- *
11
- * Each chain:
12
- * 1. Prints a banner showing the steps
13
- * 2. Runs step 1 (capture output)
14
- * 3. Prints step 1 results
15
- * 4. Asks for confirmation (or auto-continues with --yes)
16
- * 5. Runs step 2 with step 1 output as context
17
- * 6. Prints final results
18
- *
19
- * Export: getChain(name), listChains()
20
- * CLI: node agent-chains.mjs --list
21
- * node agent-chains.mjs --run <chain> [flags]
22
- */
23
-
24
- import { spawnSync } from 'child_process';
25
- import { createInterface } from 'readline';
26
- import { dirname, resolve } from 'path';
27
- import { fileURLToPath } from 'url';
28
-
29
- const __dirname = dirname(fileURLToPath(import.meta.url));
30
- const TEMPLATES_SCRIPT = resolve(__dirname, 'agent-templates.mjs');
31
-
32
- // ─── Chain Definitions ─────────────────────────────────────────────────────
33
-
34
- /**
35
- * Built-in chains.
36
- *
37
- * Each chain has:
38
- * name - unique identifier
39
- * description - one-line description
40
- * steps - array of step descriptors
41
- * step.label - human-readable step label
42
- * step.template - agent-templates.mjs template name
43
- * step.tier - search | execute | think
44
- * step.model - haiku | sonnet | opus
45
- * step.args - function(flags, prevOutput) → args object for the template
46
- * step.stop_after - if true, pause here for confirmation before continuing
47
- * step.stop_label - label for the stop-point prompt
48
- */
49
- export const CHAINS = {
50
- 'explore-then-fix': {
51
- name: 'explore-then-fix',
52
- description: 'Understand the problem, then fix it',
53
- steps: [
54
- {
55
- label: 'Step 1: Explore',
56
- template: 'explorer',
57
- tier: 'search',
58
- model: 'haiku',
59
- args: (flags) => ({
60
- question: flags.question,
61
- scope: flags.scope,
62
- }),
63
- stop_after: true,
64
- stop_label: 'Exploration complete. Review findings above, then confirm the fix.',
65
- },
66
- {
67
- label: 'Step 2: Fix',
68
- template: 'bug-hunter',
69
- tier: 'execute',
70
- model: 'sonnet',
71
- args: (flags, prevOutput) => ({
72
- question: flags.question,
73
- scope: flags.scope,
74
- context: prevOutput,
75
- }),
76
- },
77
- ],
78
- },
79
-
80
- 'review-and-test': {
81
- name: 'review-and-test',
82
- description: 'Review the code, then write tests for weak spots',
83
- steps: [
84
- {
85
- label: 'Step 1: Security Review',
86
- template: 'security-review',
87
- tier: 'think',
88
- model: 'opus',
89
- args: (flags) => ({
90
- scope: flags.scope,
91
- file: flags.file,
92
- }),
93
- stop_after: true,
94
- stop_label: 'Review complete. Review findings above, then confirm test writing.',
95
- },
96
- {
97
- label: 'Step 2: Write Tests',
98
- template: 'test-writer',
99
- tier: 'execute',
100
- model: 'sonnet',
101
- args: (flags, prevOutput) => ({
102
- scope: flags.scope,
103
- file: flags.file,
104
- context: prevOutput,
105
- }),
106
- },
107
- ],
108
- },
109
-
110
- 'audit-and-plan': {
111
- name: 'audit-and-plan',
112
- description: 'Audit the architecture, then create an execution plan',
113
- steps: [
114
- {
115
- label: 'Step 1: Architecture Audit',
116
- template: 'explorer',
117
- tier: 'search',
118
- model: 'haiku',
119
- args: (flags) => ({
120
- question: flags.question,
121
- scope: flags.scope,
122
- }),
123
- stop_after: true,
124
- stop_label: 'Audit complete. Review findings above, then confirm planning.',
125
- },
126
- {
127
- label: 'Step 2: Create Plan',
128
- template: null, // Think tier — runs via plan-generator concept inline
129
- tier: 'think',
130
- model: 'opus',
131
- args: (flags, prevOutput) => ({
132
- question: flags.question,
133
- scope: flags.scope,
134
- context: prevOutput,
135
- }),
136
- // Uses a custom prompt builder instead of an agent template
137
- custom_prompt: (flags, prevOutput) => {
138
- const scopeLine = flags.scope ? `\nScope: ${flags.scope}` : '';
139
- return [
140
- `You are an architect. Based on the audit findings below, create a detailed execution plan.`,
141
- ``,
142
- `Question / Goal: ${flags.question || 'Improve the architecture based on audit findings'}`,
143
- scopeLine,
144
- ``,
145
- `Audit findings:`,
146
- prevOutput,
147
- ``,
148
- `Produce a structured plan with:`,
149
- `- Decision: the recommended approach`,
150
- `- Rationale: why this approach over alternatives`,
151
- `- Alternatives considered (and why rejected)`,
152
- `- Risks and mitigations`,
153
- `- Verification plan: how to confirm success`,
154
- `- Task table: dependency-ordered list of concrete tasks with tier/risk`,
155
- ].join('\n');
156
- },
157
- },
158
- ],
159
- },
160
- };
161
-
162
- // ─── Exports ───────────────────────────────────────────────────────────────
163
-
164
- /**
165
- * Get a chain by name. Returns null if not found.
166
- */
167
- export function getChain(name) {
168
- return CHAINS[name] || null;
169
- }
170
-
171
- /**
172
- * List all chains as { name, description, steps }.
173
- */
174
- export function listChains() {
175
- return Object.values(CHAINS).map(({ name, description, steps }) => ({
176
- name,
177
- description,
178
- steps: steps.map(s => ({
179
- label: s.label,
180
- template: s.template,
181
- tier: s.tier,
182
- model: s.model,
183
- })),
184
- }));
185
- }
186
-
187
- // ─── Chain Execution ───────────────────────────────────────────────────────
188
-
189
- function banner(chain) {
190
- const width = 60;
191
- const line = '─'.repeat(width);
192
- console.log(`\n ${line}`);
193
- console.log(` Chain: ${chain.name} — ${chain.description}`);
194
- console.log(` ${line}`);
195
- for (let i = 0; i < chain.steps.length; i++) {
196
- const s = chain.steps[i];
197
- const model = s.model || (s.tier === 'think' ? 'opus' : s.tier === 'search' ? 'haiku' : 'sonnet');
198
- const tmpl = s.template || 'custom';
199
- console.log(` ${i + 1}. ${s.label} [${s.tier} / ${model} / ${tmpl}]`);
200
- }
201
- console.log(` ${line}\n`);
202
- }
203
-
204
- function separator(label) {
205
- const width = 60;
206
- const line = '─'.repeat(width);
207
- console.log(`\n ${line}`);
208
- if (label) console.log(` ${label}`);
209
- console.log(` ${line}\n`);
210
- }
211
-
212
- function runTemplate(templateName, templateArgs) {
213
- const argsList = ['--run', templateName];
214
- if (templateArgs.question) argsList.push('--question', templateArgs.question);
215
- if (templateArgs.scope) argsList.push('--scope', templateArgs.scope);
216
- if (templateArgs.file) argsList.push('--file', templateArgs.file);
217
- if (templateArgs.context) argsList.push('--context', templateArgs.context);
218
-
219
- const result = spawnSync(process.execPath, [TEMPLATES_SCRIPT, ...argsList], {
220
- encoding: 'utf8',
221
- stdio: ['pipe', 'pipe', 'inherit'],
222
- timeout: 30_000,
223
- });
224
-
225
- return {
226
- output: result.stdout || '',
227
- status: result.status,
228
- stderr: result.stderr || '',
229
- };
230
- }
231
-
232
- function runCustomStep(step, flags, prevOutput) {
233
- const prompt = step.custom_prompt(flags, prevOutput);
234
- const model = step.model || 'opus';
235
- const tier = step.tier || 'think';
236
-
237
- console.log(`\n [${step.label}] tier=${tier} model=${model} custom\n`);
238
- console.log('─'.repeat(60));
239
- console.log(prompt);
240
- console.log('─'.repeat(60));
241
-
242
- return {
243
- output: prompt,
244
- status: 0,
245
- };
246
- }
247
-
248
- async function askConfirmation(stopLabel) {
249
- console.log(`\n ${stopLabel}`);
250
- const rl = createInterface({ input: process.stdin, output: process.stdout });
251
- return new Promise((resolve) => {
252
- rl.question('\n Continue to step 2? [Y/n] ', (answer) => {
253
- rl.close();
254
- const ans = answer.trim().toLowerCase();
255
- resolve(ans === '' || ans === 'y' || ans === 'yes');
256
- });
257
- });
258
- }
259
-
260
- async function executeChain(chain, flags) {
261
- banner(chain);
262
-
263
- let prevOutput = '';
264
-
265
- for (let i = 0; i < chain.steps.length; i++) {
266
- const step = chain.steps[i];
267
- const isLast = i === chain.steps.length - 1;
268
-
269
- console.log(`\n Running ${step.label}...`);
270
-
271
- let result;
272
- if (step.template) {
273
- const templateArgs = step.args(flags, prevOutput);
274
- result = runTemplate(step.template, templateArgs);
275
- } else if (step.custom_prompt) {
276
- result = runCustomStep(step, flags, prevOutput);
277
- } else {
278
- console.error(` Step "${step.label}" has no template or custom_prompt.`);
279
- process.exit(1);
280
- }
281
-
282
- if (result.status !== 0) {
283
- console.error(`\n Step failed (exit ${result.status}). Chain aborted.`);
284
- process.exit(result.status || 1);
285
- }
286
-
287
- // Print step output
288
- separator(`Results: ${step.label}`);
289
- if (result.output.trim()) {
290
- console.log(result.output);
291
- } else {
292
- console.log(' (no output)');
293
- }
294
-
295
- prevOutput = result.output;
296
-
297
- // Stop point: ask for confirmation before next step
298
- if (step.stop_after && !isLast) {
299
- if (flags.yes) {
300
- console.log(`\n [--yes] Auto-continuing to next step...`);
301
- } else {
302
- const confirmed = await askConfirmation(step.stop_label || `Step ${i + 1} complete.`);
303
- if (!confirmed) {
304
- console.log('\n Aborted by user. Findings saved above.\n');
305
- process.exit(0);
306
- }
307
- }
308
- }
309
- }
310
-
311
- separator('Chain Complete');
312
- console.log(' All steps finished. Review results above.\n');
313
- }
314
-
315
- // ─── CLI ───────────────────────────────────────────────────────────────────
316
-
317
- function parseArgs(argv) {
318
- const flags = { yes: false };
319
- for (let i = 0; i < argv.length; i++) {
320
- const a = argv[i];
321
- if (a === '--list') flags.list = true;
322
- else if (a === '--run') flags.run = argv[++i];
323
- else if (a === '--question') flags.question = argv[++i];
324
- else if (a === '--scope') flags.scope = argv[++i];
325
- else if (a === '--file') flags.file = argv[++i];
326
- else if (a === '--yes' || a === '-y') flags.yes = true;
327
- }
328
- return flags;
329
- }
330
-
331
- if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
332
- const flags = parseArgs(process.argv.slice(2));
333
-
334
- if (flags.list) {
335
- console.log('\n Agent Chains:\n');
336
- for (const c of listChains()) {
337
- console.log(` ${c.name.padEnd(22)} ${c.description}`);
338
- for (const s of c.steps) {
339
- const tmpl = s.template || 'custom';
340
- console.log(` ${s.label.padEnd(30)} [${s.tier}/${s.model}/${tmpl}]`);
341
- }
342
- console.log('');
343
- }
344
- process.exit(0);
345
- }
346
-
347
- if (flags.run) {
348
- const chain = getChain(flags.run);
349
- if (!chain) {
350
- console.error(` Unknown chain: ${flags.run}`);
351
- console.error(` Available: ${Object.keys(CHAINS).join(', ')}`);
352
- process.exit(1);
353
- }
354
-
355
- executeChain(chain, flags).catch((err) => {
356
- console.error(` Chain error: ${err.message}`);
357
- process.exit(1);
358
- });
359
- } else {
360
- console.log(`
361
- Usage:
362
- node agent-chains.mjs --list
363
- node agent-chains.mjs --run explore-then-fix --question "what's wrong with auth" [--scope "src/auth"] [--yes]
364
- node agent-chains.mjs --run review-and-test [--scope "src/api"] [--file "src/api.ts"] [--yes]
365
- node agent-chains.mjs --run audit-and-plan --question "how should we restructure auth" [--scope "src/"] [--yes]
366
- `);
367
- process.exit(0);
368
- }
369
- }