diff --git a/cmd/launch/hermes.go b/cmd/launch/hermes.go index 22e93d99..9c8ffe07 100644 --- a/cmd/launch/hermes.go +++ b/cmd/launch/hermes.go @@ -152,7 +152,7 @@ func (h *HermesDesktop) launchArgs(args []string) []string { } func (h *HermesDesktop) shouldSkipDesktopBuild(args []string) bool { - if hermesDesktopHasFlag(args, "--skip-build", "--source", "--build-only", "--help", "-h") { + if hermesDesktopHasFlag(args, "--skip-build", "--force-build", "--source", "--build-only", "--help", "-h") { return false } return h.packagedAppExists() diff --git a/cmd/launch/hermes_test.go b/cmd/launch/hermes_test.go index bcdcaf71..186c9258 100644 --- a/cmd/launch/hermes_test.go +++ b/cmd/launch/hermes_test.go @@ -349,6 +349,46 @@ func TestHermesConfigureUsesLaunchResolvedHostForModelDiscovery(t *testing.T) { } } +func TestHermesConfigurePreservesExplicitCloudModel(t *testing.T) { + tmpDir := t.TempDir() + setTestHome(t, tmpDir) + withHermesPlatform(t, "darwin") + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api/tags": + fmt.Fprint(w, `{"models":[{"name":"qwen3.5:cloud"},{"name":"gemma4"}]}`) + default: + http.NotFound(w, r) + } + })) + defer srv.Close() + withHermesOllamaURL(t, srv.URL) + + if err := (&Hermes{}).Configure("qwen3.5:cloud"); err != nil { + t.Fatalf("Configure returned error: %v", err) + } + + data, err := os.ReadFile(filepath.Join(tmpDir, ".hermes", "config.yaml")) + if err != nil { + t.Fatal(err) + } + + var cfg map[string]any + if err := yaml.Unmarshal(data, &cfg); err != nil { + t.Fatalf("failed to parse rewritten yaml: %v", err) + } + modelCfg, _ := cfg["model"].(map[string]any) + if got, _ := modelCfg["default"].(string); got != "qwen3.5:cloud" { + t.Fatalf("expected explicit cloud model to be preserved, got %q", got) + } + providers, _ := cfg["providers"].(map[string]any) + provider, _ := providers[hermesProviderKey].(map[string]any) + if got, _ := provider["default_model"].(string); got != "qwen3.5:cloud" { + t.Fatalf("expected provider default model to be preserved, got %q", got) + } +} + func TestHermesConfigureMigratesLegacyManagedAliases(t *testing.T) { tmpDir := t.TempDir() setTestHome(t, tmpDir) @@ -678,6 +718,13 @@ func TestHermesDesktopRun(t *testing.T) { hasPackage: true, want: "[desktop --skip-build]", }, + { + name: "force build", + goos: runtime.GOOS, + args: []string{"--force-build"}, + hasPackage: true, + want: "[desktop --force-build]", + }, { name: "source mode", goos: runtime.GOOS, diff --git a/docs/integrations/hermes-desktop.mdx b/docs/integrations/hermes-desktop.mdx index 7126649b..66ba6e95 100644 --- a/docs/integrations/hermes-desktop.mdx +++ b/docs/integrations/hermes-desktop.mdx @@ -14,7 +14,7 @@ ollama launch hermes-desktop Ollama handles the setup flow automatically: -1. **Install** - If Hermes Desktop isn't installed, Ollama prompts to install it +1. **Install** - If Hermes isn't installed, Ollama prompts to install the Hermes command-line agent. On first desktop launch, Hermes builds its packaged desktop app. 2. **Model** - Pick a model from the selector 3. **Configure** - Ollama configures Hermes Desktop to use your selected Ollama model 4. **Launch** - Ollama opens Hermes Desktop @@ -26,3 +26,13 @@ ollama launch hermes-desktop --model ``` Run `ollama launch hermes-desktop` again to switch models later. + +## Install Hermes Desktop directly + +On macOS and Windows, the Hermes Desktop installer is the recommended upstream installation path. It installs the desktop app and Hermes Agent together. If you prefer the command line, `ollama launch hermes-desktop` remains the explicit Ollama-managed path and uses the same Hermes configuration, sessions, skills, and memory as the CLI. + +To force Hermes to rebuild its packaged desktop app: + +```bash +ollama launch hermes-desktop -- --force-build +``` diff --git a/docs/integrations/hermes.mdx b/docs/integrations/hermes.mdx index 99dda32f..d4b77a20 100644 --- a/docs/integrations/hermes.mdx +++ b/docs/integrations/hermes.mdx @@ -14,7 +14,7 @@ ollama launch hermes Ollama handles everything automatically: -1. **Install** — If Hermes isn't installed, Ollama prompts to install it via the Nous Research install script +1. **Install** — If Hermes isn't installed, Ollama prompts to install the Hermes command-line agent 2. **Model** — Pick a model from the selector (local or cloud) 3. **Onboarding** — Ollama configures the Ollama provider, points Hermes at `http://127.0.0.1:11434/v1`, and sets your model as the primary 4. **Gateway** — Optionally connects a messaging platform (Telegram, Discord, Slack, WhatsApp, Signal, Email) and launches the Hermes chat @@ -45,10 +45,10 @@ hermes gateway setup ## Reconfigure -Re-run the full setup wizard at any time: +Use Hermes's model picker to change providers or models later: ```bash -hermes setup +hermes model ``` ## Manual setup @@ -106,7 +106,7 @@ Optionally connect a messaging platform during setup: Connect a messaging platform? (Telegram, Discord, etc.) → Set up messaging now (recommended) - Skip — set up later with 'hermes setup gateway' + Skip — set up later with 'hermes gateway setup' ``` ### Launch @@ -114,4 +114,3 @@ Connect a messaging platform? (Telegram, Discord, etc.) ``` Launch hermes chat now? [Y/n]: Y ``` -