--- phase: 28-ollama-integration plan: 02 type: execute wave: 2 depends_on: [28-01] files_modified: - ui/src/api/ollama.ts - ui/src/adapters/hermes-local/config-fields.tsx - ui/src/pages/AgentDetail.tsx autonomous: true requirements: [OLLA-02, OLLA-03, OLLA-05, HERM-05] must_haves: truths: - "When Ollama is installed, the Hermes agent config shows a model dropdown listing all locally pulled models" - "When an Ollama model is selected, adapterConfig saves model + provider:custom + base_url:http://localhost:11434/v1" - "When Ollama is absent, the config shows an install callout with a link to https://ollama.com/download" - "Recommended models are visually highlighted in the dropdown" - "Hermes native skills show an 'Hermes skill' badge in the Skills tab" - "Manual model entry still works as fallback when Ollama is absent" artifacts: - path: "ui/src/api/ollama.ts" provides: "API client for Ollama status and model listing" exports: ["ollamaApi"] - path: "ui/src/adapters/hermes-local/config-fields.tsx" provides: "Ollama model dropdown, install callout, manual fallback" contains: "ollamaApi" - path: "ui/src/pages/AgentDetail.tsx" provides: "Hermes skill badge in AgentSkillsTab" contains: "Hermes skill" key_links: - from: "ui/src/adapters/hermes-local/config-fields.tsx" to: "ui/src/api/ollama.ts" via: "useQuery + ollamaApi.status / ollamaApi.models" pattern: "ollamaApi" - from: "ui/src/adapters/hermes-local/config-fields.tsx" to: "server/src/routes/ollama.ts" via: "fetch /companies/:companyId/ollama/*" pattern: "ollama" --- Create the UI surface for Ollama model selection in Hermes agent config and improve Hermes skill visibility. Purpose: Users can discover, browse, and select local Ollama models when configuring a Hermes agent, with hardware-aware recommendations highlighted. When Ollama is absent, users see install instructions. Hermes native skills are clearly labeled in the Skills tab. Output: Working model selector dropdown, install callout, and Hermes skill badges. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/28-ollama-integration/28-RESEARCH.md @.planning/phases/28-ollama-integration/28-01-SUMMARY.md @ui/src/adapters/hermes-local/config-fields.tsx @ui/src/adapters/types.ts @ui/src/api/client.ts @ui/src/pages/AgentDetail.tsx (AgentSkillsTab around line 2362, unmanagedSkillRows around 2566) GET /api/companies/:companyId/ollama/status Response: { installed: boolean; version: string | null; installUrl: string } GET /api/companies/:companyId/ollama/models Response: { models: OllamaModel[]; ramGb: number } Where OllamaModel = { name: string; // e.g. "qwen2.5-coder:32b" parameterSize: string; // e.g. "32.8B" quantization: string; // e.g. "Q4_K_M" sizeBytes: number; family: string; // e.g. "qwen2" recommended: boolean; recommendationReason: string | null; } AdapterConfigFieldsProps: { mode, isCreate, adapterType, values, set, config, eff, mark, models, hideInstructionsFile } Task 1: Create ollamaApi client and enhance HermesLocalConfigFields with model dropdown ui/src/api/ollama.ts, ui/src/adapters/hermes-local/config-fields.tsx - ui/src/api/client.ts (full file — for api.get pattern) - ui/src/api/health.ts (for simple API client pattern) - ui/src/adapters/hermes-local/config-fields.tsx (full file — current state) - ui/src/adapters/types.ts (AdapterConfigFieldsProps interface) - .planning/phases/28-ollama-integration/28-RESEARCH.md (Pattern 3, Pattern 4, Pitfall 1, Pitfall 4) 1. Create `ui/src/api/ollama.ts`: - Import `api` from "./client" (the request helper) - Define types: `OllamaStatus { installed: boolean; version: string | null; installUrl: string }`, `OllamaModel { name: string; parameterSize: string; quantization: string; sizeBytes: number; family: string; recommended: boolean; recommendationReason: string | null }`, `OllamaModelsResponse { models: OllamaModel[]; ramGb: number }` - Export `ollamaApi` object with: - `status(companyId: string): Promise` — GET `/companies/${companyId}/ollama/status` - `models(companyId: string): Promise` — GET `/companies/${companyId}/ollama/models` 2. Rewrite `ui/src/adapters/hermes-local/config-fields.tsx`: - Add imports: `useQuery` from `@tanstack/react-query`, `ollamaApi` from `../../api/ollama` - Need companyId: extract from URL params using `useParams` from react-router-dom, or accept via a context. Check existing config-fields patterns for how companyId is obtained — look at the component's parent to find how it gets companyId. If not available via props, use `useParams<{ companyId?: string }>()` matching the route pattern `/companies/:companyId/agents/...`. - Add two queries (only enabled when companyId is truthy): ``` const { data: ollamaStatus } = useQuery({ queryKey: ["ollama", "status", companyId], queryFn: () => ollamaApi.status(companyId!), enabled: Boolean(companyId), staleTime: 60_000 }) const { data: ollamaModels } = useQuery({ queryKey: ["ollama", "models", companyId], queryFn: () => ollamaApi.models(companyId!), enabled: Boolean(companyId && ollamaStatus?.installed), staleTime: 60_000 }) ``` - Replace the current free-text Model `` with a hybrid control: - **When ollamaStatus?.installed AND ollamaModels?.models.length > 0**: Render a `