diff --git a/desktop/src-tauri/src/managed_agents/discovery.rs b/desktop/src-tauri/src/managed_agents/discovery.rs
index ab76965259..2406ab286c 100644
--- a/desktop/src-tauri/src/managed_agents/discovery.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery.rs
@@ -398,6 +398,12 @@ fn command_search_dirs() -> Vec<PathBuf> {
             .ok()
             .and_then(|path| path.parent().map(Path::to_path_buf)),
     );
+
+    // Tauri-bundled sidecars are staged here by scripts/bundle-sidecars.sh.
+    // Include the directory so local dev builds can resolve them even though
+    // they carry the host target-triple suffix (e.g. buzz-agent-aarch64-apple-darwin).
+    dirs.push(workspace_root_dir().join("desktop/src-tauri/binaries"));
+
     dirs.into_iter().fold(Vec::new(), |mut unique, dir| {
         if !unique.contains(&dir) {
             unique.push(dir);
@@ -433,10 +439,21 @@ fn resolve_workspace_command(command: &str) -> Option<PathBuf> {
     }
 
     let file_name = executable_basename(command);
-    command_search_dirs()
-        .into_iter()
-        .map(|dir| dir.join(&file_name))
-        .find(|candidate| is_executable_file(candidate))
+    let triple = host_target_triple();
+    let mut basenames = vec![file_name];
+    if triple != "unknown" {
+        basenames.push(format!("{command}-{triple}"));
+    }
+
+    for dir in command_search_dirs() {
+        for basename in &basenames {
+            let candidate = dir.join(basename);
+            if is_executable_file(&candidate) {
+                return Some(candidate);
+            }
+        }
+    }
+    None
 }
 
 fn resolve_cache() -> &'static std::sync::Mutex<std::collections::HashMap<String, Option<PathBuf>>>
@@ -549,6 +566,20 @@ pub(crate) fn availability_drift(
     }
 }
 
+/// Host target triple used by Tauri-bundled sidecars (e.g. `buzz-agent-aarch64-apple-darwin`).
+fn host_target_triple() -> &'static str {
+    // ponytail: stdlib env::consts gives OS/ARCH; vendor is apple on macOS and unknown on Linux.
+    match (std::env::consts::OS, std::env::consts::ARCH) {
+        ("macos", "aarch64") => "aarch64-apple-darwin",
+        ("macos", "x86_64") => "x86_64-apple-darwin",
+        ("linux", "x86_64") => "x86_64-unknown-linux-gnu",
+        ("linux", "aarch64") => "aarch64-unknown-linux-gnu",
+        ("windows", "x86_64") => "x86_64-pc-windows-msvc",
+        ("windows", "aarch64") => "aarch64-pc-windows-msvc",
+        _ => "unknown",
+    }
+}
+
 /// Return all candidate basenames for `command` on the current platform.
 ///
 /// Always includes `executable_basename(command)` (appends `.exe` on Windows).
diff --git a/desktop/src/features/agents/AGENTS.md b/desktop/src/features/agents/AGENTS.md
index 2af9ddb98c..e55eaa0df6 100644
--- a/desktop/src/features/agents/AGENTS.md
+++ b/desktop/src/features/agents/AGENTS.md
@@ -102,6 +102,14 @@ with a TypeScript lookup table or an id comparison in a component.
    Edit. In Edit,
    selecting Custom command keeps its required command field beside the harness
    picker rather than hiding it in Advanced.
+10. **Provider-specific credential fields are a structured view over env vars.**
+    The `openai-compat` provider surfaces `OPENAI_COMPAT_BASE_URL` as a
+    dedicated input (`PersonaProviderBaseUrlField`) that writes the same env
+    var the backend already consumes. Like the API key pseudo-field, it is
+    hidden from the generic Advanced env editor and preserved across provider
+    switches so users do not lose typed values when flipping back. Provider
+    checks in these pseudo-fields (e.g. `effectiveProvider === "openai-compat"`)
+    are limited to credential presentation, not capability gating.
 
 ## The tests that enforce this
 
diff --git a/desktop/src/features/agents/ui/AgentConfigFields.tsx b/desktop/src/features/agents/ui/AgentConfigFields.tsx
index 1bd8af8976..6f6c363502 100644
--- a/desktop/src/features/agents/ui/AgentConfigFields.tsx
+++ b/desktop/src/features/agents/ui/AgentConfigFields.tsx
@@ -43,6 +43,7 @@ import {
   AgentModelField,
 } from "@/features/agents/ui/agentConfigControls";
 import { PersonaProviderApiKeyField } from "@/features/agents/ui/PersonaProviderApiKeyField";
+import { PersonaProviderBaseUrlField } from "@/features/agents/ui/PersonaProviderBaseUrlField";
 import { usePersonaModelDiscovery } from "@/features/agents/ui/usePersonaModelDiscovery";
 import {
   BUZZ_AGENT_THINKING_EFFORT,
@@ -63,6 +64,8 @@ export const EMPTY_GLOBAL_CONFIG: GlobalAgentConfig = {
   preferred_runtime: null,
 };
 
+const OPENAI_COMPAT_BASE_URL_ENV_KEY = "OPENAI_COMPAT_BASE_URL";
+
 /** Baked env keys that route to structured controls, not the generic env editor. */
 const BAKED_STRUCTURED_KEYS = new Set([
   "BUZZ_AGENT_PROVIDER",
@@ -293,6 +296,28 @@ export function AgentConfigFields({
   // CLI-login harnesses apply this setting through ACP rather than an env var
   // and provide their own default when no model override is persisted.
   const modelIsOptional = modelField?.targetApplication.kind === "acpNative";
+  const bakedEnvKeys = React.useMemo(
+    () => bakedEnv.map((entry) => entry.key),
+    [bakedEnv],
+  );
+  const baseUrlValue =
+    effectiveProvider === "openai-compat"
+      ? (config.env_vars[OPENAI_COMPAT_BASE_URL_ENV_KEY] ?? "")
+      : "";
+  const isBaseUrlRequired =
+    effectiveProvider === "openai-compat" &&
+    !bakedEnvKeys.includes(OPENAI_COMPAT_BASE_URL_ENV_KEY);
+  const isBaseUrlValid = (() => {
+    const trimmed = baseUrlValue.trim();
+    if (trimmed.length === 0) return !isBaseUrlRequired;
+    try {
+      // eslint-disable-next-line no-new
+      new URL(trimmed);
+      return true;
+    } catch {
+      return false;
+    }
+  })();
   const modelIsValid =
     modelIsOptional ||
     (config.model?.trim().length ?? 0) > 0 ||
@@ -331,10 +356,6 @@ export function AgentConfigFields({
   )
     ? selectedRuntimeId
     : "buzz-agent";
-  const bakedEnvKeys = React.useMemo(
-    () => bakedEnv.map((entry) => entry.key),
-    [bakedEnv],
-  );
   const {
     advancedCredentialMissing,
     advancedFileSatisfiedEnvKeys,
@@ -352,7 +373,10 @@ export function AgentConfigFields({
     runtimeId: credentialRuntimeId,
   });
   const configIsValid =
-    selectedRuntimeId.length > 0 && modelIsValid && credentialsValid;
+    selectedRuntimeId.length > 0 &&
+    modelIsValid &&
+    credentialsValid &&
+    isBaseUrlValid;
   React.useEffect(() => {
     onValidityChange?.(configIsValid);
   }, [configIsValid, onValidityChange]);
@@ -770,6 +794,26 @@ export function AgentConfigFields({
         </div>
       ) : null}
 
+      {providerFieldVisible && effectiveProvider === "openai-compat" ? (
+        <div className={blockClassName}>
+          <PersonaProviderBaseUrlField
+            disabled={false}
+            isRequired={isBaseUrlRequired}
+            label="OpenAI-compatible base URL"
+            onValueChange={(value) =>
+              onConfigChange({
+                ...config,
+                env_vars: {
+                  ...config.env_vars,
+                  [OPENAI_COMPAT_BASE_URL_ENV_KEY]: value,
+                },
+              })
+            }
+            value={baseUrlValue}
+          />
+        </div>
+      ) : null}
+
       {/* Model field — omitted only after confirmed successful empty discovery */}
       {modelControlVisible ? (
         <div className={showDescriptions ? fieldClassName : undefined}>
@@ -909,7 +953,11 @@ export function AgentConfigFields({
                 >
                   <EnvVarsEditor
                     fileSatisfiedKeys={advancedFileSatisfiedEnvKeys}
-                    hiddenKeys={apiKeyEnvVar ? [apiKeyEnvVar] : []}
+                    hiddenKeys={
+                      apiKeyEnvVar
+                        ? [apiKeyEnvVar, OPENAI_COMPAT_BASE_URL_ENV_KEY]
+                        : [OPENAI_COMPAT_BASE_URL_ENV_KEY]
+                    }
                     inheritedRows={bakedGenericRows}
                     inheritedRowsLabel="build"
                     label="Environment variables"
@@ -927,7 +975,11 @@ export function AgentConfigFields({
           ) : advancedOpen ? (
             <EnvVarsEditor
               fileSatisfiedKeys={advancedFileSatisfiedEnvKeys}
-              hiddenKeys={apiKeyEnvVar ? [apiKeyEnvVar] : []}
+              hiddenKeys={
+                apiKeyEnvVar
+                  ? [apiKeyEnvVar, OPENAI_COMPAT_BASE_URL_ENV_KEY]
+                  : [OPENAI_COMPAT_BASE_URL_ENV_KEY]
+              }
               inheritedRows={bakedGenericRows}
               inheritedRowsLabel="build"
               label="Environment variables"
diff --git a/desktop/src/features/agents/ui/PersonaProviderBaseUrlField.tsx b/desktop/src/features/agents/ui/PersonaProviderBaseUrlField.tsx
new file mode 100644
index 0000000000..303bfa983f
--- /dev/null
+++ b/desktop/src/features/agents/ui/PersonaProviderBaseUrlField.tsx
@@ -0,0 +1,90 @@
+import * as React from "react";
+
+import { cn } from "@/shared/lib/cn";
+import { Input } from "@/shared/ui/input";
+import { RequiredFieldLabel } from "./agentConfigControls";
+import {
+  PERSONA_FIELD_CONTROL_CLASS,
+  PERSONA_FIELD_SHELL_CLASS,
+} from "./agentConfigOptions";
+
+/** Validate that a non-empty string is parseable as a URL. */
+export function isValidUrl(value: string): boolean {
+  const trimmed = value.trim();
+  if (trimmed.length === 0) return false;
+  try {
+    // eslint-disable-next-line no-new
+    new URL(trimmed);
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+/**
+ * Base URL pseudo-field for the OpenAI-compatible provider.
+ *
+ * Mirrors PersonaProviderApiKeyField: it is a pure view over an env var
+ * (OPENAI_COMPAT_BASE_URL) and shares the same styled shell. The value is
+ * not a secret, so it renders as a plain URL input with format validation.
+ */
+export function PersonaProviderBaseUrlField({
+  disabled,
+  isRequired,
+  label,
+  onValueChange,
+  value,
+}: {
+  disabled: boolean;
+  /** True when the base URL must be provided for the selected provider. */
+  isRequired: boolean;
+  /** Display label, e.g. "OpenAI-compatible base URL". */
+  label: string;
+  onValueChange: (next: string) => void;
+  /** Current agent-local value of the base URL env var. */
+  value: string;
+}) {
+  const [touched, setTouched] = React.useState(false);
+  const inputId = "persona-provider-base-url";
+  const trimmedValue = value.trim();
+  const showError =
+    touched && trimmedValue.length > 0 && !isValidUrl(trimmedValue);
+
+  return (
+    <div className="space-y-1.5">
+      <RequiredFieldLabel htmlFor={inputId} isRequired={isRequired}>
+        {label}
+      </RequiredFieldLabel>
+      <div
+        className={cn(
+          "flex min-h-11 items-center gap-2 px-3",
+          PERSONA_FIELD_SHELL_CLASS,
+        )}
+      >
+        <Input
+          autoComplete="off"
+          className={cn(
+            "h-8 flex-1 px-0 py-0 leading-6",
+            PERSONA_FIELD_CONTROL_CLASS,
+          )}
+          data-testid="persona-provider-base-url"
+          disabled={disabled}
+          id={inputId}
+          onBlur={() => setTouched(true)}
+          onChange={(event) => onValueChange(event.target.value)}
+          placeholder="Paste OpenAI-compatible base URL"
+          type="url"
+          value={value}
+        />
+      </div>
+      {showError ? (
+        <p
+          className="text-sm text-destructive"
+          data-testid="persona-provider-base-url-error"
+        >
+          Enter a valid URL (e.g. https://api.venice.ai/v1).
+        </p>
+      ) : null}
+    </div>
+  );
+}
diff --git a/desktop/src/features/agents/ui/agentConfigFieldsContract.test.mjs b/desktop/src/features/agents/ui/agentConfigFieldsContract.test.mjs
index 7bb3888b34..6a9c633524 100644
--- a/desktop/src/features/agents/ui/agentConfigFieldsContract.test.mjs
+++ b/desktop/src/features/agents/ui/agentConfigFieldsContract.test.mjs
@@ -25,6 +25,7 @@ import {
   shouldRenderModelControl,
   shouldShowModelStatusMessage,
 } from "./AgentConfigFields.tsx";
+import { isValidUrl } from "./PersonaProviderBaseUrlField.tsx";
 
 test("canonical behaviors: onboarding's values are the only behavior", () => {
   assert.deepEqual(CANONICAL_CONFIG_BEHAVIORS, {
@@ -218,3 +219,19 @@ test("required-model harnesses always keep the control", () => {
     "required-model harnesses always keep the control",
   );
 });
+
+// ── Base URL validation ───────────────────────────────────────────────────────
+// The OpenAI-compatible provider exposes a structured base URL field that
+// writes OPENAI_COMPAT_BASE_URL. The same validation runs on input.
+
+test("isValidUrl_accepts_https_urls", () => {
+  assert.equal(isValidUrl("https://api.venice.ai/v1"), true);
+  assert.equal(isValidUrl("https://api.openai.com/v1"), true);
+});
+
+test("isValidUrl_rejects_empty_or_malformed_urls", () => {
+  assert.equal(isValidUrl(""), false);
+  assert.equal(isValidUrl("   "), false);
+  assert.equal(isValidUrl("not-a-url"), false);
+  assert.equal(isValidUrl("api.venice.ai/v1"), false);
+});
diff --git a/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.test.mjs b/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.test.mjs
index b10aa19154..bb5e23d1a3 100644
--- a/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.test.mjs
+++ b/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.test.mjs
@@ -12,11 +12,11 @@ function runtime(id, availability, status) {
   return { id, availability, authStatus: { status } };
 }
 
-test("only Claude Code and Codex are visible in onboarding", () => {
+test("Claude Code, Codex, and Buzz Agent are visible in onboarding", () => {
   assert.equal(runtimeIsVisibleInOnboarding("claude"), true);
   assert.equal(runtimeIsVisibleInOnboarding("codex"), true);
+  assert.equal(runtimeIsVisibleInOnboarding("buzz-agent"), true);
   assert.equal(runtimeIsVisibleInOnboarding("goose"), false);
-  assert.equal(runtimeIsVisibleInOnboarding("buzz-agent"), false);
   assert.equal(runtimeIsVisibleInOnboarding("custom"), false);
 });
 
@@ -30,7 +30,7 @@ test("visible onboarding runtimes use the product order", () => {
 
   assert.deepEqual(
     getVisibleOnboardingRuntimes(runtimes).map(({ id }) => id),
-    ["claude", "codex"],
+    ["claude", "codex", "buzz-agent"],
   );
 });
 
@@ -55,7 +55,7 @@ test("readiness requires an available and authenticated runtime", () => {
   );
 });
 
-test("ready onboarding runtimes exclude hidden ready harnesses", () => {
+test("ready onboarding runtimes include visible ready harnesses", () => {
   const runtimes = [
     runtime("goose", "available", "not_applicable"),
     runtime("codex", "available", "logged_out"),
@@ -65,6 +65,6 @@ test("ready onboarding runtimes exclude hidden ready harnesses", () => {
 
   assert.deepEqual(
     getReadyOnboardingRuntimes(runtimes).map(({ id }) => id),
-    ["claude"],
+    ["claude", "buzz-agent"],
   );
 });
diff --git a/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.ts b/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.ts
index 51339e2afe..66427fac41 100644
--- a/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.ts
+++ b/desktop/src/features/onboarding/ui/onboardingRuntimeSelection.ts
@@ -1,6 +1,6 @@
 import type { AcpRuntimeCatalogEntry } from "@/shared/api/types";
 
-export const ONBOARDING_RUNTIME_ORDER = ["claude", "codex"];
+export const ONBOARDING_RUNTIME_ORDER = ["claude", "codex", "buzz-agent"];
 
 const VISIBLE_ONBOARDING_RUNTIME_IDS = new Set<string>(
   ONBOARDING_RUNTIME_ORDER,
