"use client"; import { useEffect, useState } from "react"; import { Save, CheckCircle2 } from "lucide-react"; import { PageHeader } from "@/components/common/page-header"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Separator } from "@/components/ui/separator"; import { SETTINGS_CHANGED_EVENT } from "@/hooks/use-settings"; import type { ClaudeCodeHookConfig, ClaudeSmartConfig, OptimizerMode, } from "@/lib/types"; export default function ConfigureEnvPage() { const [config, setConfig] = useState(null); const [hookConfig, setHookConfig] = useState(null); const [hookDirty, setHookDirty] = useState(false); const [apiKeyDirty, setApiKeyDirty] = useState(false); const [error, setError] = useState(null); const [saved, setSaved] = useState(false); const [saving, setSaving] = useState(false); useEffect(() => { Promise.all([ fetch("/api/config", { cache: "no-store" }).then((r) => r.json()), fetch("/api/claude-settings", { cache: "no-store" }).then((r) => r.json(), ), ]) .then(([envConfig, claudeConfig]) => { setConfig(envConfig); setHookConfig(claudeConfig); setHookDirty(false); setApiKeyDirty(false); }) .catch((e) => setError(e instanceof Error ? e.message : String(e))); }, []); const update = ( key: K, value: ClaudeSmartConfig[K], ) => { setConfig((prev) => (prev ? { ...prev, [key]: value } : prev)); setSaved(false); }; const updateOptimizer = (mode: OptimizerMode) => { setHookConfig((prev) => prev ? { ...prev, CLAUDE_SMART_ENABLE_OPTIMIZER: mode, effectiveValue: mode, localValue: mode === "auto" ? null : mode, } : prev, ); setHookDirty(true); setSaved(false); }; const save = async () => { if (!config || !hookConfig) return; setSaving(true); setError(null); try { const envUpdate: Partial = { ...config }; if (!apiKeyDirty) delete envUpdate.REFLEXIO_API_KEY; delete envUpdate.REFLEXIO_API_KEY_SET; const [envRes, hookRes] = await Promise.all([ fetch("/api/config", { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify(envUpdate), }), fetch("/api/claude-settings", { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify( hookDirty ? { CLAUDE_SMART_ENABLE_OPTIMIZER: hookConfig.CLAUDE_SMART_ENABLE_OPTIMIZER, } : {}, ), }), ]); if (!envRes.ok) throw new Error(`environment save failed: ${envRes.status}`); if (!hookRes.ok) throw new Error(`Claude Code settings save failed: ${hookRes.status}`); const updated: ClaudeSmartConfig = await envRes.json(); const updatedHook: ClaudeCodeHookConfig = await hookRes.json(); setConfig(updated); setHookConfig(updatedHook); window.dispatchEvent(new Event(SETTINGS_CHANGED_EVENT)); setHookDirty(false); setApiKeyDirty(false); setSaved(true); } catch (e) { setError(e instanceof Error ? e.message : String(e)); } finally { setSaving(false); } }; return ( <> {saving ? "Saving…" : "Save"} } />
{error && (
{error}
)} {saved && (
Saved to ~/.reflexio/.env and Claude Code settings
)}

claude-smart environment

Writes to ~/.reflexio/.env. Unknown keys are preserved. These values are read by the Reflexio backend.

{config === null && !error ? (
Loading…
) : config ? (
update("REFLEXIO_URL", e.target.value)} className="font-mono text-xs bg-background/80" placeholder="http://localhost:8071/" />
{ setApiKeyDirty(true); update("REFLEXIO_API_KEY", e.target.value); }} className="font-mono text-xs bg-background/80" placeholder={ config.REFLEXIO_API_KEY_SET ? "(configured - leave blank to keep existing key)" : "(empty - local mode)" } autoComplete="off" />

Route generation through the local claude CLI.

update("CLAUDE_SMART_USE_LOCAL_CLI", v) } />

Use in-process ONNX embedder (offline-friendly).

update("CLAUDE_SMART_USE_LOCAL_EMBEDDING", v) } />

Keep session context available but skip publishing interactions to Reflexio.

update("CLAUDE_SMART_READ_ONLY", v)} />
update("CLAUDE_SMART_CLI_PATH", e.target.value)} className="font-mono text-xs bg-background/80" placeholder="(empty — auto-detect via $PATH)" />
update("CLAUDE_SMART_CLI_TIMEOUT", e.target.value) } className="font-mono text-xs bg-background/80" placeholder="120" />
update("CLAUDE_SMART_STATE_DIR", e.target.value) } className="font-mono text-xs bg-background/80" placeholder="(empty — default ~/.claude-smart/sessions)" />
) : null}

Claude Code hook environment

Writes to{" "} .claude/settings.local.json. Hook-side env changes apply to new Claude Code sessions.

{hookConfig === null && !error ? (
Loading…
) : hookConfig ? (

Control shared skill optimization and rollups during SessionStart. Auto applies only to local Reflexio.

Effective value {formatSettingValue(hookConfig.effectiveValue)}
Project override {formatSettingValue(hookConfig.localValue)}
User setting {formatSettingValue(hookConfig.userValue)}

Project file:{" "} {hookConfig.settingsPath}

User file:{" "} {hookConfig.userSettingsPath}

) : null}
); } function formatSettingValue(value: OptimizerMode | null): string { if (value === null) return "Not set"; if (value === "auto") return "Auto (local only)"; return value === "enabled" ? "Enabled" : "Disabled"; }