Run Hermes Fully Locally with QVAC A developer guide explains how to run the Hermes agent fully locally using QVAC, an OpenAI-compatible server, enabling offline inference, persistent memory, and tool execution without cloud dependencies. The setup requires a Unix-like environment, Node.js, Python, and a local model, with an acceptance test that verifies generation, tool calling, durable memory, and offline operation. Run Hermes Fully Locally with QVAC | Agent Lab Journal AL Agent Lab Journal Guides Glossary LOCAL AI AGENTS · PRACTICAL DEPLOYMENT Level: advanced Reading time: 45 minutes Result: local Hermes + QVAC + offline verification By the end of this guide, you will have a personal Hermes Agent that sends inference requests only to a model running on your machine, preserves memory between sessions, invokes a restricted set of local tools, and completes a repeatable task after the internet connection is disabled. No cloud API key is required during operation, although you must download the software and model files beforehand. Hermes Agent is the agent layer around a language model. It manages conversations, state, memory, skills, tool descriptions, and the loop that connects a model request to an actual action. QVAC is responsible for running the model locally and exposing it through an OpenAI-compatible HTTP interface. User │ ▼ Hermes Agent ├── local sessions ├── persistent memory ├── skills and policies └── restricted tools │ │ HTTP over 127.0.0.1 ▼ QVAC OpenAI server │ ▼ local model │ ▼ CPU / GPU / RAM The roles must remain separate. The large language model produces a response or requests a function. Hermes controls the agent loop, memory, permissions, and function execution. QVAC loads the model weights, applies the model's chat template, and performs local inference. In this guide, “fully local” has a precise and limited meaning: Hermes and QVAC run on one computer, or inside an isolated local environment; model requests are sent only to 127.0.0.1; sessions, memory, skills, configuration, and logs remain on local storage; the tools used by the acceptance test require no external services; after dependencies and weights have been downloaded, the scenario passes without internet access. A local model does not automatically create a secure system. A tool can still execute a command, read an unrelated file, or contact an external address. Offline operation reduces one part of the attack surface; it does not replace operating-system permissions, path validation, or approval controls. A greeting is too weak to prove that an agent works. Our acceptance case therefore uses a small project directory and tests four independent layers: generation, tool calling, durable memory, and the absence of a required cloud route. Hermes must: read a local meeting note; extract the project, decision, and next action; write a Markdown summary inside an allowed output directory; remember a harmless formatting preference; recover that preference in a new session; repeat a new file task after external networking is disabled. Create a dedicated laboratory directory. Do not begin with your home directory, a repository containing credentials, or a cloud-synchronized folder. mkdir -p "$PWD/hermes-local-lab/inbox" mkdir -p "$PWD/hermes-local-lab/outbox" printf '%s\n' \ 'Project: local assistant.' \ 'Decision: store final notes as Markdown.' \ 'Next action: verify operation without a network.' \ "$PWD/hermes-local-lab/inbox/meeting.txt" export LAB DIR="$PWD/hermes-local-lab" find "$LAB DIR" -maxdepth 2 -type f -print printf 'Laboratory directory: %s\n' "$LAB DIR" Keep this terminal open or record the absolute value of LAB DIR. Agent prompts should use an absolute path rather than relying on an uncertain working directory. You need a Unix-like environment, Node.js and npm for QVAC, a Python environment supported by the Hermes release you install, Git, curl, and enough disk space for the selected model. On Windows, use WSL2 unless the current release explicitly documents another supported route. Before changing the machine, record the software and available resources: uname -a node --version npm --version python3 --version git --version curl --version | head -n 1 df -h . free -h 2 /dev/null || true CLI flags, model identifiers, and configuration formats can change between releases. Treat every command below as a configuration for the installed version, not as permission to ignore its built-in help. If a flag is rejected, stop and inspect --help instead of guessing a replacement. After installing QVAC, use its diagnostics to identify the available compute backend: qvac doctor A supported GPU backend can reduce latency, while CPU execution may still be adequate for a small model. The actual result depends on the machine, model build, context length, and runtime version; this article does not claim universal speed or memory measurements. Begin with a model variant using 4-bit quantization. Quantization reduces the storage and memory cost of weights, but it does not eliminate runtime buffers or the memory consumed by the context cache. The QVAC model registry available in your installed release is the source of truth. List or inspect that registry before copying a model identifier into the configuration. If the following identifiers are not present in your release, select the corresponding supported instruct model and use its exact identifier. Deployment profile Example model class Use QVAC identifier used below Installation check Qwen 4B, Q4 HTTP route and simple functions QWEN3 5 4B MULTIMODAL Q4 K M Balanced laboratory Qwen 9B, Q4 More reliable argument generation QWEN3 5 9B MULTIMODAL Q4 K M Larger agent workload Qwen 35B-A3B MoE, Q4 Longer multi-step work on capable hardware QWEN3 6 35B A3B MULTIMODAL Q4 K M A mixture-of-experts model activates only part of its expert network for each token, but its weights and working data still have to fit the runtime's memory strategy. Leave capacity for the operating system, Hermes, the context, and the KV cache. The smallest model is useful for validating the route, but it may emit invalid function arguments or skip steps. A larger model can improve agent behavior, yet no model size guarantees correct tool use. First complete the whole test with a model that fits comfortably; compare alternatives only after the infrastructure is stable. Internet access is required at this stage to retrieve the package and, later, the model weights. npm install -g @qvac/cli command -v qvac qvac --help qvac doctor If global npm installation asks for administrator privileges, do not solve it by piping an unreviewed process into sudo. Configure a user-owned npm prefix or use a managed Node.js installation. Confirm that the discovered qvac binary belongs to the installation you intended. Create a separate QVAC project directory: mkdir -p "$PWD/qvac-hermes" cd "$PWD/qvac-hermes" pwd The HTTP server loads models declared under serve.models. The object key becomes the model name visible to clients. Using a stable alias keeps Hermes independent of the underlying registry identifier. Create qvac.config.json in the current directory: { "serve": { "models": { "hermes-local": { "model": "QWEN3 6 35B A3B MULTIMODAL Q4 K M", "default": true, "preload": true, "config": { "ctx size": 65536, "tools": true } } } } } For a smaller model, change only the model value to an identifier verified in your installed QVAC registry, for example: "QWEN3 5 4B MULTIMODAL Q4 K M" or: "QWEN3 5 9B MULTIMODAL Q4 K M" ctx size is the maximum context the runtime attempts to hold. Hermes may send a large system instruction plus multiple tool schemas before the user's task begins. A small context can overflow early, while a large token limit increases KV-cache memory. If 65,536 tokens do not fit, lower the value, expose fewer tools, and configure Hermes with the same effective limit. Do not advertise a larger context to Hermes than QVAC can actually serve. The tools option enables function handling for the selected model. Without it, ordinary chat can succeed while the agent returns prose instead of a structured call. Bind QVAC to the loopback interface so that other devices cannot reach the port through the LAN. cd /absolute/path/to/qvac-hermes qvac serve openai \ --config "$PWD/qvac.config.json" \ --host 127.0.0.1 \ --port 11434 \ --verbose Keep this process in a dedicated terminal. The first start may download weights before loading them into memory. Wait until server initialization has completed. From another terminal, inspect the model endpoint: curl --fail --silent --show-error \ http://127.0.0.1:11434/v1/models The returned JSON should contain the client-facing identifier hermes-local. An empty list usually means the model is not ready. A 404 indicates a route, configuration, or CLI-version mismatch. Now send a minimal completion: curl --fail --silent --show-error \ http://127.0.0.1:11434/v1/chat/completions \ -H 'Content-Type: application/json' \ -d '{ "model": "hermes-local", "messages": { "role": "user", "content": "Reply with exactly one word: ready" } , "temperature": 0, "max tokens": 16 }' Validate the response structure rather than punctuation or capitalization. It must contain a choices array with an assistant message. If HTTP succeeds but content is empty, inspect the verbose QVAC log and verify that the chosen registry entry is a chat-capable instruct model. This test separates QVAC and model behavior from the agent runtime. The described function performs no action; the request only asks the model to return a structured intention. curl --fail --silent --show-error \ http://127.0.0.1:11434/v1/chat/completions \ -H 'Content-Type: application/json' \ -d '{ "model": "hermes-local", "messages": { "role": "user", "content": "Find the size of /lab/inbox/meeting.txt. Do not guess; use the function." } , "tools": { "type": "function", "function": { "name": "get file size", "description": "Return the size of an allowed local file", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "Absolute path to the file" } }, "required": "path" , "additionalProperties": false } } } , "tool choice": "auto", "temperature": 0, "max tokens": 256 }' A successful result is not an alleged byte count. It is an item in message.tool calls whose function name is get file size and whose arguments value contains valid JSON with the requested path. Fail the test if: the model says that it will call a function but returns no tool calls; the function name is changed; arguments cannot be parsed as JSON; the model invents a file size; the requested path is replaced with another path. Do not install or debug Hermes until this boundary works. Confirm that "tools": true is active, restart QVAC after configuration changes, and test a more capable model if necessary. Successful chat completion is not evidence of successful function calling. Review remote installation scripts before executing them. One cautious sequence is: curl --fail --silent --show-error \ https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh \ -o /tmp/hermes-install.sh less /tmp/hermes-install.sh bash /tmp/hermes-install.sh If your environment prohibits remote installation scripts, follow the manual installation procedure for the release you selected. Avoid mixing system Python packages with unrelated virtual environments. Open a new terminal if the installer changed PATH, then verify the command: command -v hermes hermes --help Hermes commonly stores user state under ~/.hermes/. That directory can contain sessions, memory, skills, logs, and provider configuration. Do not publish it or commit it to Git. find "$HOME/.hermes" -maxdepth 2 -type d -print 2 /dev/null Use Hermes' interactive model configuration so that the installed release writes its own supported configuration structure: hermes model Select a custom OpenAI-compatible endpoint and enter: API base URL: http://127.0.0.1:11434/v1 API key: local-qvac Model name: hermes-local Context length: 65536 If QVAC was started without an API-key requirement, local-qvac is merely a non-empty local placeholder for clients that require a value. It is not a cloud credential and must not be copied from a real account. The corresponding configuration is conceptually equivalent to: model: default: hermes-local provider: custom base url: http://127.0.0.1:11434/v1 The exact YAML structure can change. Do not replace the entire Hermes configuration with this short example: the existing file may also contain memory, channel, and skill settings. Confirm the saved route without printing credential fields: grep -nE 'provider:|base url:|default:' \ "$HOME/.hermes/config.yaml" The base URL should begin with http://127.0.0.1:11434/v1 http://127.0.0.1:11434/v1 , and no cloud provider domain should appear in the active model configuration. hermes Begin with a generation-only request: State the configured model name and base URL. Do not use tools and do not access the network. The model's answer is not authoritative. It can repeat prompt text or hallucinate configuration. The sources of truth are the Hermes configuration, QVAC request logs, and network observation. Next, establish an explicit working boundary: Working directory: /absolute/path/hermes-local-lab You may read only from inbox. You may write only to outbox. Do not modify source files. Do not make network requests. First present a plan, then wait for my next instruction. If the agent immediately changes files, stop it. A prompt influences model behavior but does not create an isolation boundary. File permissions and tool-level validation must enforce the same policy. The precise skill and permission controls depend on the installed Hermes version, but the security rule does not: expose the smallest directory and the smallest set of operations required by the task. The laboratory needs only these capabilities: read a file from the approved input directory; list files inside the laboratory; create a new file in outbox; read and write Hermes' local memory through its dedicated interface; request approval for anything outside those boundaries. Do not enable a browser, email, messaging, unrestricted shell access, or external MCP servers for this test. If Hermes runs in a container, expose individual directories rather than the entire home directory: php /host/hermes-local-lab/inbox - /lab/inbox:ro /host/hermes-local-lab/outbox - /lab/outbox:rw /host/hermes-state - /home/hermes/.hermes:rw For a native process, use a dedicated operating-system account or another isolation mechanism. Natural-language instructions remain useful, but the operating system must reject access that the agent should not have. An allowlist must compare normalized absolute paths. A raw string-prefix check can be bypassed with .., alternate separators, or symbolic links. requested path │ ▼ resolve with realpath │ ├── inside inbox → read ├── inside outbox → read and create └── elsewhere → deny Give Hermes this task after replacing with the absolute laboratory path: Read: