APNext H3 LLM Backend (Ollama / local / API)
Run every H3 writer on Ollama instead of the Claude Code CLI
- llm
- model_used
Here's the deal with the Claude Code H3 writers: they default to your locally installed Claude Code CLI, using its login and your subscription seat. That's great until you don't have a Claude subscription, or you'd rather the whole thing be free, offline, and uncensored. APNext H3 LLM Backend is the one-node answer: pick a model here, drag its pink llm output into any number of H3 writers' llm sockets, and those nodes stop calling the CLI and write with whatever you chose - Ollama, LM Studio, any OpenAI-compatible server, or a cloud API model.
This is the local-vs-API decision the LLM-in-the-graph world keeps landing on: for the job of "turn a short idea into a structured, spec-compliant prompt," an 8B model on your own card is enough, and it buys you three things an API can't - it's uncensored, it's free per call, and it never phones home. The node's model dropdown lists every ollama: / lmstudio: / local: model your servers were serving when the ComfyUI page loaded, then the cloud API models, then custom.
The inputs that matter
model- discovered local models, cloud entries, or custom (the default). The dropdown is built at page load, so start your server before reloading ComfyUI.model_name- used with custom, and it's the escape hatch for anything undiscovered:ollama:qwen3:8b,lmstudio:qwen/qwen3-8b,local:my-model, evenclaude:claude-sonnet-5. A bareqwen3:8bis understood as an Ollama tag.base_url- point a node at a LAN box or odd port, likehttp://192.168.1.10:11434. Empty uses the prefix default: Ollama on 11434, LM Studio on 1234,local:on 8000.temperatureandmax_tokens- sampling and answer length. Multi-scene crossover runs need headroom; leavemax_tokensat 8000 unless you're hitting truncation.inline_skill_references- the sleeper. With the writer'sdirectoron, this pastes the H3 director skills' whole reference library (gold examples, grammar, style anchors) into the system prompt instead of just the rules. Noticeably better prompts - and it needs a big context window, so raise Ollama'snum_ctxwhen you flip it on.
Outputs: llm (the socket you connect) and model_used (what actually answered, handy for the info-style housekeeping).
What changes off the CLI
Three things quietly swap when you go local: research is ignored (a local model has no web tools), the director skills are pasted into the system prompt rather than Read from disk, and session_id / resume_session_id still work but through a text-only local session kept under ComfyUI's temp folder. A Claude Code session id can't be resumed with a local model and vice versa - the error says exactly that. Everything else - wardrobe locks, template variables, outputs - is identical, so you can A/B a Claude run and an Ollama run of the same workflow without changing anything else.
Installing and troubleshooting
Same pack as the rest of H3: ComfyUI Manager, search comfyui_dagthomas; or clone https://github.com/dagthomas/comfyui_dagthomas into custom_nodes and pip install -r requirements.txt (openai, anthropic, google-genai, httpx, huggingface_hub, chardet). Then restart.
The classic traps: a model not in the dropdown almost always means the server wasn't running when the page loaded - start Ollama, refresh, it appears. The probe can be disabled entirely with APNEXT_LOCAL_LLM_DISCOVERY=0 if it's ever slow or noisy. If you connect images, the model must be vision-capable - ollama:qwen3-vl:8b or similar, or the vision input is silently wasted. And if you've been burned by this pack before: an early 2024 release changed the working directory on load and broke ComfyUI's restart button; that was fixed long ago (PR #8), so don't let an old horror story stop you. Unplug the llm socket and the writer drops straight back onto Claude Code - the backend is fully optional.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| model | COMBO | custom (use model_name below) | ollama: / lmstudio: / local: entries are whatever your local servers were serving when the page loaded (start the server, reload the page). Cloud entries need their API key in the environment - or typed into api_key below. openrouter: entries are OpenRouter's whole text-model catalogue, fetched when the page loaded (curated ones first, then A-Z; type to filter) - one key for all of them (OPENROUTER_API_KEY). Pick 'custom' to type any provider:model string in model_name. |
| model_name | STRING | ollama:qwen3:8b | Used when model = custom. Any router string: 'ollama:qwen3:8b', 'lmstudio:qwen/qwen3-8b', 'local:my-model', 'claude:claude-sonnet-5', 'gpt:gpt-5.6', 'gemini:gemini-3.7-flash', 'openrouter:<vendor/model>' (any id from openrouter.ai/models) - or the Codex CLI: 'codex' (its configured model) / 'codex:<model-id>' for a specific one. |
| base_url | STRING | http://0.0.0.0:11434 | Where to reach a local server. The default is Ollama's own port on this machine (0.0.0.0 / a wildcard is read as localhost). A LAN box or another port goes here, e.g. 'http://192.168.1.10:11434'. Empty uses the default for the prefix: ollama 11434, lmstudio 1234, local 8000 (or OLLAMA_BASE_URL / LMSTUDIO_BASE_URL / LOCAL_LLM_BASE_URL). Ignored by cloud providers. |
| temperature | FLOAT | 1.000–2 | — |
| max_tokens | INT | 8000256–128000 | Answer length cap. Multi-scene crossover / scenes runs need room. |
| inline_skill_references | COMBO | off (skill rules only) | With the H3 node's director on: how much of the skills' reference library is pasted into the system prompt (a local model cannot Read files). essentials keeps what teaches the format - the prompt grammar, the gold examples and the style anchors - and is the best quality per token. full library adds the style-picker catalogues and mode docs too; the system prompt then passes 60k tokens and Ollama needs num_ctx 131072. Workflows saved with the old on/off switch load as essentials/off. |
| num_ctx | INT | 1310720–1048576 | Ollama only: the context window to load the model with. Ollama picks its own default from free VRAM - as little as 4k - and an H3 system prompt is 9-15k tokens on its own, so on a small default the writing rules are silently cut off and the scenes come back unusable. 32k is enough for a text-only run, 40k+ with reference images or inline_skill_references; 131072 measured fully GPU-resident for qwen3.8:27b (hybrid attention, light KV) on a 32 GB card - a dense KV-heavy model may need less to stay on the GPU (watch `ollama ps`: size_vram should equal size). 0 = leave the server's default alone. Ignored by every other provider (LM Studio, vLLM and the cloud APIs set their context elsewhere). |
| thinking | COMBO | off (faster - recommended) | Ollama only: whether a hybrid reasoning model (Qwen3, DeepSeek-R1, gpt-oss, ...) reasons before answering. Off is much faster and the H3 rules are already in the system prompt. Any <think> block that does arrive is stripped before parsing either way. Models with no thinking mode ignore this. |
| unload_after | BOOLEAN | true | Ollama only: once a writer has all its scenes, ask Ollama to drop the model from VRAM right away instead of keeping it for its keep_alive window, so the memory is back for the video render that follows. Off keeps it loaded (faster if another writer runs next). |
| structured_output | COMBO | auto (JSON with a schema on Ollama, text envelopes elsewhere) | How multi-scene answers travel back. auto: on Ollama the reply is JSON constrained by a schema (valid by construction - no envelope to mis-write), other backends keep the text envelopes. on: every backend is asked for JSON (not enforced off Ollama; the text envelopes remain the fallback). off: text envelopes everywhere. The scene text itself is unchanged either way. |
| api_keyopt | STRING | API key for a cloud provider on this node - OpenRouter, OpenAI, Grok, Groq - used instead of the environment variable when set. The key is saved INSIDE the workflow JSON in plain text: fine on your own machine, but on a shared box or before sharing a workflow, leave this empty and set OPENROUTER_API_KEY (etc.) in the environment instead. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| llm | APNEXT_LLM | — |
| model_used | STRING | — |