From a74af05c96b8188e8f7b7e239173311b00ecc9a7 Mon Sep 17 00:00:00 2001 From: Dan Cetlin Date: Sat, 4 Jul 2026 11:39:22 -0600 Subject: [PATCH 1/5] feat(model): configurable default + per-spawn model override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model was hardcoded in two places (bridge-dispatch SPAWN_MODEL for spawns, lifecycle.ts for the byte). This makes it selectable at two levels, with precedence: `--model` (per-spawn) > HYDRA_MODEL (config default) > built-in. - daemon/bridge-dispatch.ts: SPAWN_MODEL = HYDRA_MODEL ?? DEFAULT_MODEL - cli/lifecycle.ts: byte reads HYDRA_MODEL - daemon/session-lifecycle.ts + sessions.ts: SpawnOpts.model overrides per spawn - cli/hydra.ts + daemon/cli-handler.ts: `hydra spawn --model ` - .env.example: document HYDRA_MODEL The daemon self-loads the state .env (config.ts), so HYDRA_MODEL reaches spawns without touching buildDaemonEnvs. Do nothing → identical to today. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 1 + cli/hydra.ts | 6 +++++- cli/lifecycle.ts | 4 +++- daemon/bridge-dispatch.ts | 5 ++++- daemon/cli-handler.ts | 5 +++-- daemon/session-lifecycle.ts | 10 ++++++---- daemon/sessions.ts | 1 + 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 7ca672b..f164376 100644 --- a/.env.example +++ b/.env.example @@ -21,6 +21,7 @@ SLACK_APP_TOKEN=xapp-... # CLAUDE_CONFIG_DIR=~/.claude # must contain the bridge plugin (see docs/slack.md) # ── Optional (have sensible defaults) ── +# HYDRA_MODEL=claude-opus-4-6[1m] # default model for byte + spawns; per-spawn override: hydra spawn --model # HYDRA_STATE_DIR=~/.claude/channels/discord # state dir (socket, sessions, access) # DEFAULT_SESSION_CHANNEL= # Discord: channel for spawned threads from DMs # TMUX_SESSION=discord-daemon # tmux session name for the daemon diff --git a/cli/hydra.ts b/cli/hydra.ts index f9904d3..b20616d 100644 --- a/cli/hydra.ts +++ b/cli/hydra.ts @@ -45,6 +45,7 @@ Spawn options (required): --idempotency-key Prevent duplicate spawns --channel Target channel for the spawned thread --message Create thread on this message (requires --channel) + --model Model for this session (default: $HYDRA_MODEL or claude-opus-4-6[1m]) Global options: --daemon Target a specific daemon @@ -116,6 +117,7 @@ async function main(): Promise { let message: string | undefined let quiet = false let ephemeral = false + let model: string | undefined const promptParts: string[] = [] for (let i = 1; i < filtered.length; i++) { @@ -131,6 +133,8 @@ async function main(): Promise { quiet = true } else if (filtered[i] === '--ephemeral') { ephemeral = true + } else if (filtered[i] === '--model' && i + 1 < filtered.length) { + model = filtered[++i] } else { promptParts.push(filtered[i]) } @@ -158,7 +162,7 @@ async function main(): Promise { type: 'cli', command: 'spawn', id: randomUUID(), - params: { prompt, idempotencyKey, initiator, ...(channel && { channel }), ...(message && { message }), ...(quiet && { quiet }), ...(ephemeral && { ephemeral }) }, + params: { prompt, idempotencyKey, initiator, model, ...(channel && { channel }), ...(message && { message }), ...(quiet && { quiet }), ...(ephemeral && { ephemeral }) }, }) printResponse(response, json) break diff --git a/cli/lifecycle.ts b/cli/lifecycle.ts index 35dacb6..d85b0f2 100644 --- a/cli/lifecycle.ts +++ b/cli/lifecycle.ts @@ -65,13 +65,15 @@ export async function startByte(cfg: HydraConfig): Promise { } const byteCwd = process.env.BYTE_CWD ?? cfg.spawnCwd + // Canonical default is DEFAULT_MODEL in daemon/bridge-dispatch.ts; keep in sync. + const byteModel = process.env.HYDRA_MODEL ?? 'claude-opus-4-6[1m]' const inner = [ `cd ${shq(byteCwd)}`, `export DAEMON_SOCK=${shq(cfg.sockPath)}`, `export CLAUDE_CONFIG_DIR=${shq(cfg.configDir)}`, `export CHAT_PLATFORM=${cfg.platform}`, authExport || null, - `caffeinate -i claude --model 'claude-opus-4-6[1m]' --channels plugin:discord@claude-plugins-official --dangerously-skip-permissions ${shq(prompt)}`, + `caffeinate -i claude --model ${shq(byteModel)} --channels plugin:discord@claude-plugins-official --dangerously-skip-permissions ${shq(prompt)}`, ].filter(Boolean).join(' && ') tmuxSpawn(cfg.byteTmux, inner) diff --git a/daemon/bridge-dispatch.ts b/daemon/bridge-dispatch.ts index 100b071..ae28e05 100644 --- a/daemon/bridge-dispatch.ts +++ b/daemon/bridge-dispatch.ts @@ -52,7 +52,10 @@ export const BRIDGE_TOOLS = [ { name: 'list_watches', description: 'List all PRs being watched (your session or all).', inputSchema: { type: 'object', properties: { all: { type: 'boolean', description: 'Show all watches, not just yours' } } } }, ] -export const SPAWN_MODEL = 'claude-opus-4-6[1m]' +// Canonical default. HYDRA_MODEL overrides it for byte + all spawns; +// `hydra spawn --model ` overrides a single spawn. +export const DEFAULT_MODEL = 'claude-opus-4-6[1m]' +export const SPAWN_MODEL = process.env.HYDRA_MODEL ?? DEFAULT_MODEL export const MAIN_ONLY_TOOLS = new Set(['spawn_session', 'list_sessions', 'kill_session']) export function computeToolsForSession(sessionId: string): typeof BRIDGE_TOOLS { diff --git a/daemon/cli-handler.ts b/daemon/cli-handler.ts index 8caec09..a82e28b 100644 --- a/daemon/cli-handler.ts +++ b/daemon/cli-handler.ts @@ -62,7 +62,7 @@ function respond(req: CLIRequest, ok: boolean, dataOrError?: unknown, maybeData? // --------------------------------------------------------------------------- async function handleSpawn(req: CLIRequest): Promise { - const { prompt, initiator, idempotencyKey, channel, message, ephemeral, quiet } = req.params as { + const { prompt, initiator, idempotencyKey, channel, message, ephemeral, quiet, model } = req.params as { prompt?: string initiator?: string idempotencyKey?: string @@ -70,6 +70,7 @@ async function handleSpawn(req: CLIRequest): Promise { message?: string ephemeral?: boolean quiet?: boolean + model?: string } if (!prompt) return respond(req, false, 'prompt is required') @@ -88,7 +89,7 @@ async function handleSpawn(req: CLIRequest): Promise { let result try { - result = await doSpawnSession(prompt, channel ?? undefined, message ?? undefined, { initiator, ephemeral }) + result = await doSpawnSession(prompt, channel ?? undefined, message ?? undefined, { initiator, model, ephemeral }) } catch (err) { updateIdempotency(idempotencyKey, { status: 'failed' }) throw err diff --git a/daemon/session-lifecycle.ts b/daemon/session-lifecycle.ts index 3543b04..6c32c59 100644 --- a/daemon/session-lifecycle.ts +++ b/daemon/session-lifecycle.ts @@ -370,6 +370,8 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: prompt = buildSpawnPrompt(promptParams) } + const model = opts?.model ?? SPAWN_MODEL + // Build claude command — fork adds --resume --fork-session, resume uses --resume without fork let claudeArgs: string if (isFork) { @@ -377,7 +379,7 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: `claude`, `--resume ${shq(opts!.forkFrom!.claudeSessionId)}`, `--fork-session`, - `--model ${shq(SPAWN_MODEL)}`, + `--model ${shq(model)}`, `--channels ${shq(channelFlag)}`, `--dangerously-skip-permissions`, shq(prompt), @@ -386,12 +388,12 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: claudeArgs = [ `claude`, `--resume ${shq(opts!.resumeFrom!)}`, - `--model ${shq(SPAWN_MODEL)}`, + `--model ${shq(model)}`, `--channels ${shq(channelFlag)}`, `--dangerously-skip-permissions`, ].join(' ') } else { - claudeArgs = `claude --model ${shq(SPAWN_MODEL)} --channels ${shq(channelFlag)} --dangerously-skip-permissions ${shq(prompt)}` + claudeArgs = `claude --model ${shq(model)} --channels ${shq(channelFlag)} --dangerously-skip-permissions ${shq(prompt)}` } const inner = [ @@ -427,7 +429,7 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: const capabilities: SessionCapabilities = { role: 'worker', tools: computeToolsForSession(sessionId).map(t => t.name), - model: SPAWN_MODEL, + model, cwd: effectiveCwd, platform: PLATFORM, } diff --git a/daemon/sessions.ts b/daemon/sessions.ts index a518937..bbdfb4b 100644 --- a/daemon/sessions.ts +++ b/daemon/sessions.ts @@ -98,6 +98,7 @@ export type SpawnOpts = { memberLabel?: string // label for thread member (e.g. 'critic', 'judge') initiator?: string ephemeral?: boolean // auto-kill on [done] sentinel, skip death visuals + model?: string // per-spawn model override (falls back to SPAWN_MODEL / HYDRA_MODEL) } // --------------------------------------------------------------------------- From 5e149e13e9b2fce2e6fd1c613bc549a13cb5455c Mon Sep 17 00:00:00 2001 From: Dan Cetlin Date: Sat, 4 Jul 2026 18:21:38 -0600 Subject: [PATCH 2/5] =?UTF-8?q?fix(model):=20address=20review=20=E2=80=94?= =?UTF-8?q?=20import=20constant,=20falsy=20guard,=20spawn=5Fsession=20mode?= =?UTF-8?q?l=20passthrough?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Import DEFAULT_MODEL in lifecycle.ts instead of duplicating the string - Use || (falsy) instead of ?? (nullish) so empty-string model falls back correctly - Add model field to spawn_session bridge tool so byte can select models for spawns Co-Authored-By: Claude Opus 4.6 (1M context) --- cli/lifecycle.ts | 4 ++-- daemon/bridge-dispatch.ts | 5 +++-- daemon/session-lifecycle.ts | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/lifecycle.ts b/cli/lifecycle.ts index d85b0f2..39e5c5f 100644 --- a/cli/lifecycle.ts +++ b/cli/lifecycle.ts @@ -9,6 +9,7 @@ import { compileCheck, killOrphanBytes, hasOrphanBytes, appendLog, shq, waitForSocket, buildDaemonEnvs, } from './helpers.js' +import { DEFAULT_MODEL } from '../daemon/bridge-dispatch.js' // --------------------------------------------------------------------------- // Start byte (replaces start-byte.sh) @@ -65,8 +66,7 @@ export async function startByte(cfg: HydraConfig): Promise { } const byteCwd = process.env.BYTE_CWD ?? cfg.spawnCwd - // Canonical default is DEFAULT_MODEL in daemon/bridge-dispatch.ts; keep in sync. - const byteModel = process.env.HYDRA_MODEL ?? 'claude-opus-4-6[1m]' + const byteModel = process.env.HYDRA_MODEL || DEFAULT_MODEL const inner = [ `cd ${shq(byteCwd)}`, `export DAEMON_SOCK=${shq(cfg.sockPath)}`, diff --git a/daemon/bridge-dispatch.ts b/daemon/bridge-dispatch.ts index ae28e05..50f4261 100644 --- a/daemon/bridge-dispatch.ts +++ b/daemon/bridge-dispatch.ts @@ -43,7 +43,7 @@ export const BRIDGE_TOOLS = [ { name: 'download_attachment', description: 'Download attachments from a message.', inputSchema: { type: 'object', properties: { chat_id: { type: 'string' }, message_id: { type: 'string' } }, required: ['chat_id', 'message_id'] } }, { name: 'create_thread', description: 'Create a thread in a channel.', inputSchema: { type: 'object', properties: { chat_id: { type: 'string' }, message_id: { type: 'string' }, name: { type: 'string' }, text: { type: 'string' }, auto_archive_minutes: { type: 'number' }, files: { type: 'array', items: { type: 'string' } } }, required: ['chat_id', 'name'] } }, { name: 'fetch_messages', description: 'Fetch recent messages from a channel.', inputSchema: { type: 'object', properties: { channel: { type: 'string' }, limit: { type: 'number' } }, required: ['channel'] } }, - { name: 'spawn_session', description: 'Spawn a new Claude session. Main session only. Pass worktree with a repo directory name (e.g. "options_bot") to spawn in an isolated git worktree.', inputSchema: { type: 'object', properties: { topic: { type: 'string' }, chat_id: { type: 'string' }, message_id: { type: 'string' }, worktree: { type: 'string', description: 'Git repo subdirectory to create a worktree from (e.g. "options_bot", "anytester"). Session gets an isolated copy.' } }, required: ['topic'] } }, + { name: 'spawn_session', description: 'Spawn a new Claude session. Main session only. Pass worktree with a repo directory name (e.g. "options_bot") to spawn in an isolated git worktree.', inputSchema: { type: 'object', properties: { topic: { type: 'string' }, chat_id: { type: 'string' }, message_id: { type: 'string' }, worktree: { type: 'string', description: 'Git repo subdirectory to create a worktree from (e.g. "options_bot", "anytester"). Session gets an isolated copy.' }, model: { type: 'string', description: 'Model ID for this spawn (overrides HYDRA_MODEL).' } }, required: ['topic'] } }, { name: 'list_sessions', description: 'List all active sessions. Main session only.', inputSchema: { type: 'object', properties: {} } }, { name: 'kill_session', description: 'Kill a session by ID or thread ID. Main session only.', inputSchema: { type: 'object', properties: { session_id: { type: 'string' }, thread_id: { type: 'string' } } } }, { name: 'set_description', description: 'Set a brief description for your session.', inputSchema: { type: 'object', properties: { session_id: { type: 'string' }, description: { type: 'string' } }, required: ['session_id', 'description'] } }, @@ -206,7 +206,8 @@ export async function executeTool(name: string, args: Record, c case 'spawn_session': { const worktree = args.worktree as string | undefined const topic = worktree ? `worktree:${worktree} ${args.topic}` : args.topic as string - const result = await doSpawnSession(topic, args.chat_id as string | undefined, args.message_id as string | undefined) + const model = args.model as string | undefined + const result = await doSpawnSession(topic, args.chat_id as string | undefined, args.message_id as string | undefined, model ? { model } : undefined) return { content: [{ type: 'text', text: `session spawned (name: ${result.name}, session_id: ${result.sessionId}, thread_id: ${result.threadId}${result.url ? `, url: ${result.url}` : ''})` }] } } diff --git a/daemon/session-lifecycle.ts b/daemon/session-lifecycle.ts index 6c32c59..e78a2e4 100644 --- a/daemon/session-lifecycle.ts +++ b/daemon/session-lifecycle.ts @@ -370,7 +370,7 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: prompt = buildSpawnPrompt(promptParams) } - const model = opts?.model ?? SPAWN_MODEL + const model = opts?.model || SPAWN_MODEL // Build claude command — fork adds --resume --fork-session, resume uses --resume without fork let claudeArgs: string From d40e683774d13b2a4e03905c6980d76e41dcfceb Mon Sep 17 00:00:00 2001 From: Dan Cetlin Date: Sat, 4 Jul 2026 18:33:25 -0600 Subject: [PATCH 3/5] fix(model): use falsy check on HYDRA_MODEL env read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same empty-string bypass that was fixed for opts.model also existed at the env-read level — HYDRA_MODEL="" would resolve to "" instead of DEFAULT_MODEL. Co-Authored-By: Claude Opus 4.6 (1M context) --- daemon/bridge-dispatch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/bridge-dispatch.ts b/daemon/bridge-dispatch.ts index 50f4261..5ebd948 100644 --- a/daemon/bridge-dispatch.ts +++ b/daemon/bridge-dispatch.ts @@ -55,7 +55,7 @@ export const BRIDGE_TOOLS = [ // Canonical default. HYDRA_MODEL overrides it for byte + all spawns; // `hydra spawn --model ` overrides a single spawn. export const DEFAULT_MODEL = 'claude-opus-4-6[1m]' -export const SPAWN_MODEL = process.env.HYDRA_MODEL ?? DEFAULT_MODEL +export const SPAWN_MODEL = process.env.HYDRA_MODEL || DEFAULT_MODEL export const MAIN_ONLY_TOOLS = new Set(['spawn_session', 'list_sessions', 'kill_session']) export function computeToolsForSession(sessionId: string): typeof BRIDGE_TOOLS { From cc678d3466ce98156c8e5b4b324c59c765d06a0d Mon Sep 17 00:00:00 2001 From: Dan Cetlin Date: Sun, 5 Jul 2026 08:53:19 -0600 Subject: [PATCH 4/5] fix(model): shared constants, input normalization, ?? for internal fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review round 2 feedback: - Extract DEFAULT_MODEL to shared/constants.ts — eliminates cross-boundary import (CLI was importing from daemon module graph) - Revert session-lifecycle to ?? (nullish) — bad input should fail visibly at the claude CLI, not silently fall back. HYDRA_MODEL env read keeps || since empty-string-in-.env is a config mistake that should fall back. - Normalize model at bridge tool entry: trim + empty→undefined, so LLM callers sending { model: "" } or { model: " " } get clean fallback - Log model overrides from spawn_session for debuggability - CLI help: show full default chain ($HYDRA_MODEL or claude-opus-4-6[1m]) Co-Authored-By: Claude Opus 4.6 (1M context) --- cli/lifecycle.ts | 2 +- daemon/bridge-dispatch.ts | 9 +++++---- daemon/session-lifecycle.ts | 2 +- shared/constants.ts | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 shared/constants.ts diff --git a/cli/lifecycle.ts b/cli/lifecycle.ts index 39e5c5f..95cec12 100644 --- a/cli/lifecycle.ts +++ b/cli/lifecycle.ts @@ -9,7 +9,7 @@ import { compileCheck, killOrphanBytes, hasOrphanBytes, appendLog, shq, waitForSocket, buildDaemonEnvs, } from './helpers.js' -import { DEFAULT_MODEL } from '../daemon/bridge-dispatch.js' +import { DEFAULT_MODEL } from '../shared/constants.js' // --------------------------------------------------------------------------- // Start byte (replaces start-byte.sh) diff --git a/daemon/bridge-dispatch.ts b/daemon/bridge-dispatch.ts index 5ebd948..8a4c6ce 100644 --- a/daemon/bridge-dispatch.ts +++ b/daemon/bridge-dispatch.ts @@ -52,9 +52,9 @@ export const BRIDGE_TOOLS = [ { name: 'list_watches', description: 'List all PRs being watched (your session or all).', inputSchema: { type: 'object', properties: { all: { type: 'boolean', description: 'Show all watches, not just yours' } } } }, ] -// Canonical default. HYDRA_MODEL overrides it for byte + all spawns; -// `hydra spawn --model ` overrides a single spawn. -export const DEFAULT_MODEL = 'claude-opus-4-6[1m]' +import { DEFAULT_MODEL } from '../shared/constants.js' + +// Frozen at import time — daemon restart required to pick up changes. export const SPAWN_MODEL = process.env.HYDRA_MODEL || DEFAULT_MODEL export const MAIN_ONLY_TOOLS = new Set(['spawn_session', 'list_sessions', 'kill_session']) @@ -206,7 +206,8 @@ export async function executeTool(name: string, args: Record, c case 'spawn_session': { const worktree = args.worktree as string | undefined const topic = worktree ? `worktree:${worktree} ${args.topic}` : args.topic as string - const model = args.model as string | undefined + const model = (args.model as string | undefined)?.trim() || undefined + if (model) process.stderr.write(`daemon: spawn_session model override: ${model}\n`) const result = await doSpawnSession(topic, args.chat_id as string | undefined, args.message_id as string | undefined, model ? { model } : undefined) return { content: [{ type: 'text', text: `session spawned (name: ${result.name}, session_id: ${result.sessionId}, thread_id: ${result.threadId}${result.url ? `, url: ${result.url}` : ''})` }] } } diff --git a/daemon/session-lifecycle.ts b/daemon/session-lifecycle.ts index e78a2e4..6c32c59 100644 --- a/daemon/session-lifecycle.ts +++ b/daemon/session-lifecycle.ts @@ -370,7 +370,7 @@ export async function doSpawnSession(topic: string, chatId?: string, messageId?: prompt = buildSpawnPrompt(promptParams) } - const model = opts?.model || SPAWN_MODEL + const model = opts?.model ?? SPAWN_MODEL // Build claude command — fork adds --resume --fork-session, resume uses --resume without fork let claudeArgs: string diff --git a/shared/constants.ts b/shared/constants.ts new file mode 100644 index 0000000..0f1e3b9 --- /dev/null +++ b/shared/constants.ts @@ -0,0 +1 @@ +export const DEFAULT_MODEL = 'claude-opus-4-6[1m]' From 0015bad99d0effdfc8ef9f98c4c3c2584e70ee17 Mon Sep 17 00:00:00 2001 From: Dan Cetlin Date: Sun, 5 Jul 2026 09:06:10 -0600 Subject: [PATCH 5/5] fix(model): tsconfig include, import placement, trim env reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add cli/**/*.ts and shared/**/*.ts to tsconfig.json include — shared/constants.ts and CLI files were not type-checked - Move DEFAULT_MODEL import to top of bridge-dispatch.ts (convention) - Trim HYDRA_MODEL env reads — whitespace-only values fall back to default Co-Authored-By: Claude Opus 4.6 (1M context) --- cli/lifecycle.ts | 2 +- daemon/bridge-dispatch.ts | 5 ++--- tsconfig.json | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cli/lifecycle.ts b/cli/lifecycle.ts index 95cec12..da14a40 100644 --- a/cli/lifecycle.ts +++ b/cli/lifecycle.ts @@ -66,7 +66,7 @@ export async function startByte(cfg: HydraConfig): Promise { } const byteCwd = process.env.BYTE_CWD ?? cfg.spawnCwd - const byteModel = process.env.HYDRA_MODEL || DEFAULT_MODEL + const byteModel = process.env.HYDRA_MODEL?.trim() || DEFAULT_MODEL const inner = [ `cd ${shq(byteCwd)}`, `export DAEMON_SOCK=${shq(cfg.sockPath)}`, diff --git a/daemon/bridge-dispatch.ts b/daemon/bridge-dispatch.ts index 8a4c6ce..2ae10c7 100644 --- a/daemon/bridge-dispatch.ts +++ b/daemon/bridge-dispatch.ts @@ -7,6 +7,7 @@ import { doSpawnSession, killSession } from './session-lifecycle.js' import { fallbackDescription, formatDuration, getContextPercent, chunk, assertSendable, isAlive } from './util.js' import { watchPr, unwatchPr, listWatches, getWatchesBySession, formatWatchEntry, detectPrUrl, WATCH_ERRORS } from './pr-watch.js' import { refreshSessionVisual } from './anchor-state.js' +import { DEFAULT_MODEL } from '../shared/constants.js' const SEND_RETRY_ATTEMPTS = 3 const SEND_RETRY_BASE_MS = 1_000 @@ -52,10 +53,8 @@ export const BRIDGE_TOOLS = [ { name: 'list_watches', description: 'List all PRs being watched (your session or all).', inputSchema: { type: 'object', properties: { all: { type: 'boolean', description: 'Show all watches, not just yours' } } } }, ] -import { DEFAULT_MODEL } from '../shared/constants.js' - // Frozen at import time — daemon restart required to pick up changes. -export const SPAWN_MODEL = process.env.HYDRA_MODEL || DEFAULT_MODEL +export const SPAWN_MODEL = process.env.HYDRA_MODEL?.trim() || DEFAULT_MODEL export const MAIN_ONLY_TOOLS = new Set(['spawn_session', 'list_sessions', 'kill_session']) export function computeToolsForSession(sessionId: string): typeof BRIDGE_TOOLS { diff --git a/tsconfig.json b/tsconfig.json index 829282c..37ae797 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,6 @@ "esModuleInterop": true, "resolveJsonModule": true }, - "include": ["*.ts", "daemon/**/*.ts"], + "include": ["*.ts", "daemon/**/*.ts", "cli/**/*.ts", "shared/**/*.ts"], "exclude": ["node_modules", "slack-gateway.ts"] }