Tunnel

Local models

Use Ollama, LM Studio, vLLM or llama.cpp on your own computer as a model provider for your agents, through the tunnel.

A model server running on a connected computer can power your agents. The server stays on localhost, nothing is exposed to the internet, and the prompts and answers travel only over the tunnel's own outbound connection.

Two kinds of local server are supported:

Harness Servers Found at
ollama Ollama http://localhost:11434
openai-compatible-local LM Studio, vLLM, llama.cpp, or anything that speaks the OpenAI chat API http://localhost:1234 (LM Studio), :8000 (vLLM), :8080 (llama.cpp) — the first that answers

(Codex and Claude Code can also run on the computer as models. They work differently; see Codex and Claude Code.)

Register

Run register once, as the daemon's run-as user, with the model server running:

sudo -u <run-as-user> agentparley register

It checks each harness and prints one line per harness:

– codex                    not found
– claude                   not found
✓ ollama                   registered — 3 models
✓ openai-compatible-local  registered — 1 model

Each registered harness becomes a provider in your console, named after it and the computer (for example "Ollama (local, via tunnel) on homelab"), with one model per model the server lists. Pick those models for an agent like any other model. You change nothing in the console: the server's address and its model list stay on your computer.

Pulled a new model, or removed one? Run register again; it is safe to repeat. agentparley unregister ollama removes the provider.

Context windows

AgentParley needs each model's context window to know when to compact a long chat. register reads it from the server:

  • Ollama: the model's context_length, from /api/show.
  • llama.cpp: the context the server was actually started with (n_ctx from /props), which can be smaller than the model's trained context.
  • vLLM: max_model_len from /v1/models.

When a server doesn't report one (LM Studio, for example), give it in the config, or the model is not registered:

harnesses:
  openai-compatible-local:
    url: http://localhost:1234       # optional; overrides discovery
    models:
      - id: qwen3-32b
        label: Qwen3 32B
        context_window_tokens: 32768
  ollama:
    url: http://localhost:11434      # only needed for a non-default address

Give the server root as url; a trailing /v1 is trimmed for you.

How a request travels

agent turn ──▶ SSH egress ──▶ your daemon ──▶ POST localhost:<port>/v1/chat/completions
                                                (messages + tool definitions)
           ◀── answer or tool calls ◀──────────┘

Each model step is one request. The daemon sends the chat's messages and the agent's tools to your server's OpenAI-compatible chat endpoint, and returns the answer or the tool calls the model asked for. AgentParley runs the tools itself (SSH commands, web search, plugins, other agents) and sends the results back in the next step. Your local model therefore uses every tool your agent has, but the model server never runs a tool itself.

Things to know:

  • Use a model that supports tool calling. Agents depend on tools; a model without tool calling can only chat.
  • Text only. Images are not sent to local models.
  • One step can take up to 10 minutes. Slow hardware with a big model is fine, within that limit.
  • No per-token price. You run the hardware, so AgentParley records token counts for these models at no cost.
  • Local model requests share the computer's operation limit (max_concurrent_operations, default 8) with SSH commands.

Keeping a harness off

To stop register from ever offering a harness on a computer, deny it in the config:

deny_harnesses: ["openai-compatible-local"]   # deny always beats allow
allow_harnesses: []                           # empty = all harnesses considered

The daemon also checks this list on every request, so denying a harness that was already registered stops it at once.