@kinqs/brainrouter-cli 0.3.6 → 0.3.8

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.
Files changed (129) hide show
  1. package/README.md +29 -52
  2. package/agents/architect.json +18 -0
  3. package/agents/explorer.json +18 -0
  4. package/agents/reviewer.json +18 -0
  5. package/agents/verifier.json +18 -0
  6. package/agents/worker.json +18 -0
  7. package/changelog/0.2.0.md +15 -0
  8. package/changelog/0.3.0.md +20 -0
  9. package/changelog/0.3.1.md +22 -0
  10. package/changelog/0.3.2.md +15 -0
  11. package/changelog/0.3.3.md +19 -0
  12. package/changelog/0.3.4.md +20 -0
  13. package/changelog/0.3.5.md +9 -0
  14. package/changelog/0.3.6.md +9 -0
  15. package/changelog/0.3.7.md +20 -0
  16. package/changelog/0.3.8.md +30 -0
  17. package/changelog/README.md +41 -0
  18. package/dist/agent/agent.d.ts +34 -1
  19. package/dist/agent/agent.js +372 -79
  20. package/dist/agent/toolCallRecovery.d.ts +57 -0
  21. package/dist/agent/toolCallRecovery.js +130 -0
  22. package/dist/agent/toolSafety.d.ts +17 -0
  23. package/dist/agent/toolSafety.js +102 -0
  24. package/dist/cli/banner.d.ts +20 -0
  25. package/dist/cli/banner.js +47 -14
  26. package/dist/cli/cliPrompt.d.ts +40 -3
  27. package/dist/cli/cliPrompt.js +117 -25
  28. package/dist/cli/commands/_context.d.ts +3 -1
  29. package/dist/cli/commands/_helpers.d.ts +1 -1
  30. package/dist/cli/commands/config.d.ts +46 -0
  31. package/dist/cli/commands/config.js +1042 -0
  32. package/dist/cli/commands/init.d.ts +20 -0
  33. package/dist/cli/commands/init.js +64 -0
  34. package/dist/cli/commands/login.d.ts +13 -0
  35. package/dist/cli/commands/login.js +179 -0
  36. package/dist/cli/commands/mcp.d.ts +13 -11
  37. package/dist/cli/commands/mcp.js +261 -74
  38. package/dist/cli/commands/mcpInstall.d.ts +20 -0
  39. package/dist/cli/commands/mcpInstall.js +87 -0
  40. package/dist/cli/commands/orchestration.js +51 -0
  41. package/dist/cli/commands/releaseNotes.d.ts +24 -0
  42. package/dist/cli/commands/releaseNotes.js +109 -0
  43. package/dist/cli/commands/schedule.d.ts +18 -0
  44. package/dist/cli/commands/schedule.js +189 -0
  45. package/dist/cli/commands/ui.js +119 -60
  46. package/dist/cli/commands/workflow.d.ts +2 -0
  47. package/dist/cli/commands/workflow.js +54 -8
  48. package/dist/cli/ink/ChatApp.d.ts +206 -0
  49. package/dist/cli/ink/ChatApp.js +493 -0
  50. package/dist/cli/ink/Frame.d.ts +26 -0
  51. package/dist/cli/ink/Frame.js +5 -0
  52. package/dist/cli/ink/Picker.d.ts +71 -0
  53. package/dist/cli/ink/Picker.js +168 -0
  54. package/dist/cli/ink/SlashPalette.d.ts +51 -0
  55. package/dist/cli/ink/SlashPalette.js +136 -0
  56. package/dist/cli/ink/TextField.d.ts +34 -0
  57. package/dist/cli/ink/TextField.js +47 -0
  58. package/dist/cli/ink/WizardApp.d.ts +7 -0
  59. package/dist/cli/ink/WizardApp.js +422 -0
  60. package/dist/cli/ink/ambientChat.d.ts +34 -0
  61. package/dist/cli/ink/ambientChat.js +7 -0
  62. package/dist/cli/ink/consoleCapture.d.ts +11 -0
  63. package/dist/cli/ink/consoleCapture.js +33 -0
  64. package/dist/cli/ink/markdownRender.d.ts +41 -0
  65. package/dist/cli/ink/markdownRender.js +278 -0
  66. package/dist/cli/ink/renderWithResizeClear.d.ts +14 -0
  67. package/dist/cli/ink/renderWithResizeClear.js +33 -0
  68. package/dist/cli/ink/runChat.d.ts +34 -0
  69. package/dist/cli/ink/runChat.js +682 -0
  70. package/dist/cli/ink/runPicker.d.ts +31 -0
  71. package/dist/cli/ink/runPicker.js +139 -0
  72. package/dist/cli/ink/runSlashPalette.d.ts +23 -0
  73. package/dist/cli/ink/runSlashPalette.js +33 -0
  74. package/dist/cli/ink/runWizard.d.ts +22 -0
  75. package/dist/cli/ink/runWizard.js +133 -0
  76. package/dist/cli/ink/stdinHandoff.d.ts +51 -0
  77. package/dist/cli/ink/stdinHandoff.js +78 -0
  78. package/dist/cli/ink/toolFormat.d.ts +75 -0
  79. package/dist/cli/ink/toolFormat.js +206 -0
  80. package/dist/cli/ink/useTerminalSize.d.ts +35 -0
  81. package/dist/cli/ink/useTerminalSize.js +26 -0
  82. package/dist/cli/repl.d.ts +25 -3
  83. package/dist/cli/repl.js +52 -714
  84. package/dist/cli/slashSuggest.d.ts +32 -0
  85. package/dist/cli/slashSuggest.js +146 -0
  86. package/dist/cli/wizard/modelsApi.d.ts +72 -0
  87. package/dist/cli/wizard/modelsApi.js +166 -0
  88. package/dist/cli/wizard/picker.d.ts +202 -0
  89. package/dist/cli/wizard/picker.js +547 -0
  90. package/dist/cli/wizard/providers.d.ts +86 -0
  91. package/dist/cli/wizard/providers.js +190 -0
  92. package/dist/cli/wizard/runner.d.ts +13 -0
  93. package/dist/cli/wizard/runner.js +488 -0
  94. package/dist/cli/wizard/types.d.ts +122 -0
  95. package/dist/cli/wizard/types.js +109 -0
  96. package/dist/config/config.d.ts +13 -1
  97. package/dist/config/config.js +45 -3
  98. package/dist/index.js +157 -206
  99. package/dist/memory/briefing.d.ts +1 -1
  100. package/dist/memory/briefing.js +4 -4
  101. package/dist/memory/consolidation.d.ts +1 -1
  102. package/dist/orchestration/agentRegistry.d.ts +36 -0
  103. package/dist/orchestration/agentRegistry.js +64 -0
  104. package/dist/orchestration/orchestrator.d.ts +7 -0
  105. package/dist/orchestration/orchestrator.js +2 -0
  106. package/dist/orchestration/tools.d.ts +105 -3
  107. package/dist/orchestration/tools.js +167 -8
  108. package/dist/prompt/skillCatalog.d.ts +11 -0
  109. package/dist/prompt/skillCatalog.js +134 -0
  110. package/dist/prompt/skillRunner.d.ts +2 -2
  111. package/dist/prompt/skillRunner.js +2 -31
  112. package/dist/prompt/systemPrompt.js +7 -2
  113. package/dist/runtime/anthropicAdapter.d.ts +100 -0
  114. package/dist/runtime/anthropicAdapter.js +293 -0
  115. package/dist/runtime/cronParser.d.ts +23 -0
  116. package/dist/runtime/cronParser.js +122 -0
  117. package/dist/runtime/mcpClient.js +14 -11
  118. package/dist/runtime/mcpPool.d.ts +170 -0
  119. package/dist/runtime/mcpPool.js +442 -0
  120. package/dist/runtime/mcpUtils.d.ts +17 -1
  121. package/dist/runtime/mcpUtils.js +23 -0
  122. package/dist/runtime/scheduleTicker.d.ts +33 -0
  123. package/dist/runtime/scheduleTicker.js +99 -0
  124. package/dist/runtime/vendorSnippets.d.ts +45 -0
  125. package/dist/runtime/vendorSnippets.js +153 -0
  126. package/dist/state/scheduleStore.d.ts +37 -0
  127. package/dist/state/scheduleStore.js +64 -0
  128. package/package.json +14 -5
  129. package/.env.example +0 -116
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Per-vendor MCP install snippets (0.3.8-I5 / roadmap §9).
3
+ *
4
+ * Pattern adapted from semble's per-agent install docs
5
+ * (openSrc/semble/src/semble/agents/*.md) — one focused entry per vendor
6
+ * with the exact JSON shape and config file path. Where semble ships
7
+ * markdown, we ship structured templates so the CLI can substitute the
8
+ * user's live profile URL + API key on the fly.
9
+ *
10
+ * Notes
11
+ * - Tool name examples use the single-underscore convention
12
+ * `mcp_<server>_<tool>` (0.3.8-R5 decision).
13
+ * - Each template is pinned to a "verified against vendor docs as of …"
14
+ * comment. Vendor MCP schemas drift; bump the date when you re-verify.
15
+ * - We never auto-write the vendor config file. Print only — direct-write
16
+ * is a future enhancement (roadmap: future item; do not file a follow-up).
17
+ */
18
+ import os from 'node:os';
19
+ import path from 'node:path';
20
+ // Helpers ------------------------------------------------------------------
21
+ function home(platform) {
22
+ // Tests can override HOME / APPDATA; in production this is os.homedir().
23
+ if (platform === 'win32')
24
+ return process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming');
25
+ return os.homedir();
26
+ }
27
+ /** Render a config path for human display — backslashes on Windows. */
28
+ export function displayPath(p, platform = process.platform) {
29
+ return platform === 'win32' ? p.replace(/\//g, '\\') : p;
30
+ }
31
+ // Vendor definitions -------------------------------------------------------
32
+ export const VENDORS = {
33
+ 'claude-desktop': {
34
+ id: 'claude-desktop',
35
+ label: 'Claude Desktop',
36
+ schema: 'http',
37
+ restart: 'Quit and reopen Claude Desktop fully — it only re-reads this file on cold start.',
38
+ // Verified against Anthropic docs as of 2026-05.
39
+ configPath: (p) => p === 'win32'
40
+ ? path.join(home(p), 'Claude', 'claude_desktop_config.json')
41
+ : p === 'darwin'
42
+ ? path.join(home(p), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json')
43
+ : path.join(home(p), '.config', 'Claude', 'claude_desktop_config.json'),
44
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
45
+ mcpServers: {
46
+ [serverId]: {
47
+ url,
48
+ headers: { Authorization: `Bearer ${apiKey}` },
49
+ },
50
+ },
51
+ }),
52
+ },
53
+ cursor: {
54
+ id: 'cursor',
55
+ label: 'Cursor',
56
+ schema: 'http',
57
+ restart: 'Cursor reloads MCP servers automatically; reopen the MCP panel if the server does not appear.',
58
+ // Verified against Cursor docs as of 2026-05 (~/.cursor/mcp.json).
59
+ configPath: (p) => path.join(home(p), '.cursor', 'mcp.json'),
60
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
61
+ mcpServers: {
62
+ [serverId]: {
63
+ url,
64
+ headers: { Authorization: `Bearer ${apiKey}` },
65
+ },
66
+ },
67
+ }),
68
+ },
69
+ windsurf: {
70
+ id: 'windsurf',
71
+ label: 'Windsurf (Codeium)',
72
+ schema: 'http',
73
+ restart: 'Open the Windsurf MCP panel and click "Refresh" — no full restart needed.',
74
+ // Verified against Codeium docs as of 2026-05 (~/.codeium/windsurf/mcp_config.json).
75
+ configPath: (p) => path.join(home(p), '.codeium', 'windsurf', 'mcp_config.json'),
76
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
77
+ mcpServers: {
78
+ [serverId]: {
79
+ serverUrl: url,
80
+ headers: { Authorization: `Bearer ${apiKey}` },
81
+ },
82
+ },
83
+ }),
84
+ },
85
+ 'vscode-continue': {
86
+ id: 'vscode-continue',
87
+ label: 'VS Code (Continue extension)',
88
+ schema: 'http',
89
+ restart: 'Continue picks up config.json changes live — no reload required.',
90
+ // Verified against Continue docs as of 2026-05. MCP servers live under
91
+ // experimental.modelContextProtocolServers in ~/.continue/config.json.
92
+ configPath: (p) => path.join(home(p), '.continue', 'config.json'),
93
+ note: 'Merge this block into the top-level object — Continue keys MCP servers under `experimental.modelContextProtocolServers`.',
94
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
95
+ experimental: {
96
+ modelContextProtocolServers: [
97
+ {
98
+ name: serverId,
99
+ transport: { type: 'http', url, headers: { Authorization: `Bearer ${apiKey}` } },
100
+ },
101
+ ],
102
+ },
103
+ }),
104
+ },
105
+ zed: {
106
+ id: 'zed',
107
+ label: 'Zed',
108
+ schema: 'http',
109
+ restart: 'Zed reloads settings.json on save; reopen the assistant panel to see the new server.',
110
+ // Verified against Zed docs as of 2026-05. MCP servers live under
111
+ // `context_servers` in settings.json.
112
+ configPath: (p) => path.join(home(p), '.config', 'zed', 'settings.json'),
113
+ note: 'Merge the `context_servers` key into your existing settings.json.',
114
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
115
+ context_servers: {
116
+ [serverId]: {
117
+ source: 'custom',
118
+ url,
119
+ headers: { Authorization: `Bearer ${apiKey}` },
120
+ },
121
+ },
122
+ }),
123
+ },
124
+ cline: {
125
+ id: 'cline',
126
+ label: 'Cline (VS Code)',
127
+ schema: 'http',
128
+ restart: 'Cline reloads MCP servers when this file is saved — toggle the server off/on in the MCP panel if not.',
129
+ // Verified against Cline docs as of 2026-05.
130
+ configPath: (p) => p === 'darwin'
131
+ ? path.join(home(p), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
132
+ : p === 'win32'
133
+ ? path.join(home(p), 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
134
+ : path.join(home(p), '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
135
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
136
+ mcpServers: {
137
+ [serverId]: {
138
+ url,
139
+ headers: { Authorization: `Bearer ${apiKey}` },
140
+ },
141
+ },
142
+ }),
143
+ },
144
+ };
145
+ export function listVendors() {
146
+ return Object.values(VENDORS);
147
+ }
148
+ export function getVendor(id) {
149
+ return VENDORS[id.toLowerCase()];
150
+ }
151
+ export function renderSnippet(entry, vars) {
152
+ return JSON.stringify(entry.template(vars), null, 2);
153
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Persistent store for `/schedule` jobs.
3
+ *
4
+ * One JSON file per workspace under the user-global brainrouter home
5
+ * (same contract /feedback uses) — writes go through `writeJsonFile`
6
+ * which does the atomic temp-then-rename dance, so a Ctrl-C mid-write
7
+ * can't corrupt the file.
8
+ */
9
+ export type ScheduleKind = 'cron' | 'once';
10
+ export interface ScheduleRecord {
11
+ id: string;
12
+ kind: ScheduleKind;
13
+ /** Cron expression for `cron`, or ISO timestamp for `once`. */
14
+ expr: string;
15
+ /** Slash command to dispatch. Always starts with `/`. */
16
+ command: string;
17
+ /** sessionKey of the REPL that registered the schedule. */
18
+ owner: string;
19
+ createdAt: string;
20
+ enabled: boolean;
21
+ nextRun: string;
22
+ lastRun?: string;
23
+ }
24
+ export declare function loadSchedules(workspaceRoot: string): ScheduleRecord[];
25
+ export declare function saveSchedules(workspaceRoot: string, list: ScheduleRecord[]): void;
26
+ export interface AddScheduleInput {
27
+ kind: ScheduleKind;
28
+ expr: string;
29
+ command: string;
30
+ owner: string;
31
+ nextRun: string;
32
+ enabled?: boolean;
33
+ }
34
+ export declare function addSchedule(workspaceRoot: string, input: AddScheduleInput): ScheduleRecord;
35
+ export declare function removeSchedule(workspaceRoot: string, id: string): boolean;
36
+ export declare function setScheduleEnabled(workspaceRoot: string, id: string, enabled: boolean): boolean;
37
+ export declare function recordFire(workspaceRoot: string, id: string, firedAt: Date, nextRun: string | undefined): void;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Persistent store for `/schedule` jobs.
3
+ *
4
+ * One JSON file per workspace under the user-global brainrouter home
5
+ * (same contract /feedback uses) — writes go through `writeJsonFile`
6
+ * which does the atomic temp-then-rename dance, so a Ctrl-C mid-write
7
+ * can't corrupt the file.
8
+ */
9
+ import crypto from 'node:crypto';
10
+ import { getCliStateFile, readJsonFile, writeJsonFile } from './cliState.js';
11
+ const FILE_NAME = 'schedules.json';
12
+ const EMPTY = { version: 1, schedules: [] };
13
+ function filePath(workspaceRoot) {
14
+ return getCliStateFile(workspaceRoot, FILE_NAME);
15
+ }
16
+ export function loadSchedules(workspaceRoot) {
17
+ return readJsonFile(filePath(workspaceRoot), EMPTY).schedules ?? [];
18
+ }
19
+ export function saveSchedules(workspaceRoot, list) {
20
+ writeJsonFile(filePath(workspaceRoot), { version: 1, schedules: list });
21
+ }
22
+ export function addSchedule(workspaceRoot, input) {
23
+ const list = loadSchedules(workspaceRoot);
24
+ const rec = {
25
+ id: 'sch_' + crypto.randomBytes(4).toString('hex'),
26
+ kind: input.kind,
27
+ expr: input.expr,
28
+ command: input.command,
29
+ owner: input.owner,
30
+ createdAt: new Date().toISOString(),
31
+ enabled: input.enabled ?? true,
32
+ nextRun: input.nextRun,
33
+ };
34
+ list.push(rec);
35
+ saveSchedules(workspaceRoot, list);
36
+ return rec;
37
+ }
38
+ export function removeSchedule(workspaceRoot, id) {
39
+ const list = loadSchedules(workspaceRoot);
40
+ const next = list.filter((s) => s.id !== id);
41
+ if (next.length === list.length)
42
+ return false;
43
+ saveSchedules(workspaceRoot, next);
44
+ return true;
45
+ }
46
+ export function setScheduleEnabled(workspaceRoot, id, enabled) {
47
+ const list = loadSchedules(workspaceRoot);
48
+ const rec = list.find((s) => s.id === id);
49
+ if (!rec)
50
+ return false;
51
+ rec.enabled = enabled;
52
+ saveSchedules(workspaceRoot, list);
53
+ return true;
54
+ }
55
+ export function recordFire(workspaceRoot, id, firedAt, nextRun) {
56
+ const list = loadSchedules(workspaceRoot);
57
+ const rec = list.find((s) => s.id === id);
58
+ if (!rec)
59
+ return;
60
+ rec.lastRun = firedAt.toISOString();
61
+ if (nextRun)
62
+ rec.nextRun = nextRun;
63
+ saveSchedules(workspaceRoot, list);
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinqs/brainrouter-cli",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Memory-native terminal coding agent. Talks to the BrainRouter MCP cognitive engine for recall, skills, capture, persona, focus scenes, and contradiction tracking.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,9 @@
8
8
  "brainrouter": "bin/cli.cjs"
9
9
  },
10
10
  "files": [
11
+ "agents",
11
12
  "bin",
13
+ "changelog",
12
14
  "dist",
13
15
  "README.md",
14
16
  ".env.example"
@@ -19,24 +21,31 @@
19
21
  "dev": "tsx src/index.ts",
20
22
  "start": "node dist/index.js",
21
23
  "test": "npm run build && node --test \"dist/**/*.test.js\"",
22
- "prepack": "npm run build && find dist -name '*.test.*' -delete"
24
+ "prepack": "npm run build && find dist -name '*.test.*' -delete",
25
+ "sync-changelog": "rm -rf changelog && mkdir -p changelog && cp ../brainrouter-changelog/*.md changelog/",
26
+ "prepublishOnly": "npm run sync-changelog"
23
27
  },
24
28
  "dependencies": {
25
- "@kinqs/brainrouter-sdk": "^0.3.6",
26
- "@kinqs/brainrouter-types": "^0.3.6",
29
+ "@kinqs/brainrouter-sdk": "^0.3.8",
30
+ "@kinqs/brainrouter-types": "^0.3.8",
27
31
  "@modelcontextprotocol/sdk": "^1.11.0",
28
32
  "chalk": "^5.3.0",
29
33
  "commander": "^12.1.0",
30
34
  "dotenv": "^16.4.5",
35
+ "ink": "^7.0.3",
36
+ "ink-spinner": "^5.0.0",
37
+ "ink-text-input": "^6.0.0",
31
38
  "inquirer": "^9.3.2",
32
39
  "marked": "^12.0.1",
33
40
  "marked-terminal": "^7.0.0",
34
- "ora": "^8.0.1"
41
+ "ora": "^8.0.1",
42
+ "react": "^19.2.6"
35
43
  },
36
44
  "devDependencies": {
37
45
  "@types/inquirer": "^9.0.7",
38
46
  "@types/marked": "^4.0.8",
39
47
  "@types/node": "^22.0.0",
48
+ "@types/react": "^19.2.15",
40
49
  "tsx": "^4.7.0",
41
50
  "typescript": "^5.5.4"
42
51
  },
package/.env.example DELETED
@@ -1,116 +0,0 @@
1
- # BrainRouter CLI agent — environment template
2
- #
3
- # Copy to `brainrouter-cli/.env`. Loaded by the CLI at startup.
4
- #
5
- # This file is for CLI-AGENT concerns only:
6
- # 1. Chat LLM (the model the terminal agent talks to)
7
- # 2. Tool runtime (loop limit, result clamp, MCP timeout, auto-compact)
8
- # 3. Sandbox (run_command wrapping)
9
- # 4. Workspace (root override + shared state root)
10
- # 5. Web search (custom backend for the web_search tool)
11
- # 6. Observability (trace log path)
12
- #
13
- # MCP-server concerns (cognitive extraction, embeddings, reranker, judge,
14
- # memory engine knobs, server auth) live in `brainrouter/.env.example`.
15
- #
16
- # Why split: the MCP and the CLI are separate processes with different
17
- # concerns. The CLI's chat LLM can be a smart cloud model while the MCP's
18
- # cognitive extractor is a cheap local one. Their concurrency caps differ
19
- # too (CLI default 4, MCP default 2). Keep them independent.
20
- #
21
- # All values in this template are blank placeholders. Fill in only what
22
- # you actually need — most settings have sensible defaults.
23
-
24
-
25
- # =============================================================================
26
- # 1. Chat LLM (for the agent's own conversation)
27
- # =============================================================================
28
- # Same var names as the MCP, but a separate process — set them here for the
29
- # CLI's chat model. Falls back to OPENAI_API_KEY.
30
- #
31
- # If you don't set BRAINROUTER_LLM_API_KEY here, the CLI also reads it from
32
- # `brainrouter/.env` as a transitional fallback. Setting it here makes the
33
- # CLI's choice explicit and lets you use a different chat model than the
34
- # MCP's extractor (e.g. gpt-4o for chat, gpt-4o-mini for extraction).
35
- BRAINROUTER_LLM_API_KEY=
36
-
37
- # OpenAI-compatible chat-completions endpoint.
38
- # Examples:
39
- # OpenAI: https://api.openai.com/v1/chat/completions
40
- # OpenRouter: https://openrouter.ai/api/v1/chat/completions
41
- # Anthropic via OpenRouter: model id "anthropic/claude-sonnet-4"
42
- # LM Studio: http://localhost:1234/v1/chat/completions
43
- BRAINROUTER_LLM_ENDPOINT=https://api.openai.com/v1/chat/completions
44
- BRAINROUTER_LLM_MODEL=gpt-4o-mini
45
-
46
- # Per-call timeout for the CLI's chat LLM. Default 120000 (2 min).
47
- # BRAINROUTER_LLM_TIMEOUT_MS=120000
48
-
49
- # Cap on concurrent in-flight chat LLM calls FROM THE CLI PROCESS.
50
- # Default 4 (separate from the MCP's own cap). Set to 1 for consumer-grade
51
- # local backends; raise to 16+ for cloud APIs.
52
- # BRAINROUTER_LLM_MAX_CONCURRENT=4
53
-
54
-
55
- # =============================================================================
56
- # 2. Tool runtime
57
- # =============================================================================
58
- # Per-tool timeout for CLI → MCP requests. Default 60000.
59
- # BRAINROUTER_MCP_TIMEOUT_MS=60000
60
-
61
- # LLM-visible clamp on a single tool-result body (full text still recorded
62
- # in the transcript on disk). Default 8000.
63
- # BRAINROUTER_MAX_TOOL_RESULT_CHARS=8000
64
-
65
- # Hard ceiling on tool-call iterations per turn. Default 60.
66
- # BRAINROUTER_MAX_TOOL_LOOPS=60
67
-
68
- # Estimated history-size trigger for auto-`/compact`. Default 80000 tokens.
69
- # BRAINROUTER_AUTO_COMPACT_TOKENS=80000
70
-
71
-
72
- # =============================================================================
73
- # 3. Sandbox (run_command)
74
- # =============================================================================
75
- # Wrap shell commands in the platform sandbox:
76
- # macOS: sandbox-exec
77
- # Linux: bwrap (preferred) or firejail
78
- # Set `on` to enable. Off by default.
79
- # BRAINROUTER_SANDBOX=on
80
-
81
- # Allow outbound network from sandboxed commands. Off by default.
82
- # BRAINROUTER_SANDBOX_NETWORK=off
83
-
84
- # Colon-separated read/write path allowlists.
85
- # BRAINROUTER_SANDBOX_READ_PATHS=/usr/local:/opt
86
- # BRAINROUTER_SANDBOX_WRITE_PATHS=/tmp
87
-
88
-
89
- # =============================================================================
90
- # 4. Workspace
91
- # =============================================================================
92
- # Override the workspace root the CLI uses for file tools + session key.
93
- # Most users let the CLI auto-detect via git / closest package.json.
94
- # BRAINROUTER_WORKSPACE=/path/to/project
95
-
96
- # Override per-user state root. Default: ~/.brainrouter.
97
- # Both the CLI and MCP honor this — set it once and both processes use it.
98
- # BRAINROUTER_HOME=/path/to/state
99
-
100
-
101
- # =============================================================================
102
- # 5. Web search
103
- # =============================================================================
104
- # Custom search backend for the web_search tool. Must accept
105
- # POST { query, maxResults } → { results: [{ title, url, snippet }] }
106
- # Falls back to DuckDuckGo's Instant Answer API when unset.
107
- # Compatible with Brave Search API wrappers, Tavily, SerpAPI proxies, etc.
108
- # BRAINROUTER_WEB_SEARCH_ENDPOINT=https://your-search-proxy.example.com/search
109
-
110
-
111
- # =============================================================================
112
- # 6. Observability
113
- # =============================================================================
114
- # Path for OTEL-style JSONL turn traces. One line per turn/tool span.
115
- # Toggle at runtime with /trace on|off.
116
- # BRAINROUTER_TRACE_LOG=/path/to/trace.jsonl