A Qoder-CLI skill + standalone toolkit that routes routine, token-heavy coding work (boilerplate, docstrings, refactors, test scaffolding, translations, file summarization, code edits) to a local llama.cpp server instead of cloud models. Zero cloud tokens for delegated work.
Tested only with Qoder CLI so far — the toolkit itself is agent-agnostic (plain Python + shell), but the Claude Code and GitHub Copilot integrations are untested templates.
- Python 3.10+ (standard library only — no pip installs)
- A running (or auto-startable)
llama-serverwith the OpenAI-compatible API
-
Copy this folder to
~/.qoder/skills/local/(or anywhere). -
Create your machine-private
config.jsonfrom the template and edit it:cp config.example.json config.json
{ "url": "http://localhost:8080", "workdir": "C:/path/to/llama.cpp", "start_command": "build/bin/Release/llama-server.exe -m models/your-model.gguf --port 8080 -ngl 99 -c 80000 -np 1 --cache-prompt", "startup_timeout_s": 300 }config.jsonis gitignored; never commit your own paths/model names. -
Call the delegate:
py -3 bin/llama_delegate.py "your task prompt"If the server is down it is launched automatically from
start_command.
All commands run through one script: bin/llama_delegate.py
(Windows: py -3, Linux/macOS: python3).
# Ask the local model a task
py -3 bin/llama_delegate.py "write a docstring for: def f(x): return x * 2"
# Give it a file — the script reads it itself, cloud context stays empty
py -3 bin/llama_delegate.py "find the bug in this file" --file src/utils.py
# Big file? Take only one symbol instead of the whole file
py -3 bin/llama_delegate.py "explain this" --file big.py --focus _run_training
# Or compress a huge file into a summary first (cached by content hash)
py -3 bin/llama_delegate.py --summarize huge_file.py
# Let the model edit a file (SEARCH/REPLACE blocks, applied atomically)
py -3 bin/llama_delegate.py --patch src/utils.py "rename to snake_case" --dry-run
# ... and make it verify + self-fix: run a command after patching, and if it
# fails, the model repairs the file and re-runs it until it passes
py -3 bin/llama_delegate.py --patch src/utils.py "optimize parse()" --test "py -3 -m pytest tests -q"
# Focused helper modes (read piped stdin, keep the cloud agent out of the loop)
pytest -q 2>&1 | py -3 bin/llama_delegate.py --triage # FAILING/ERROR/LIKELY_CAUSE/NEXT
git diff | py -3 bin/llama_delegate.py --review # SUMMARY/RISKS/FOCUS pre-review
git diff | py -3 bin/llama_delegate.py --commit-msg # Conventional Commits message
some_big_log.txt | py -3 bin/llama_delegate.py --summarize-stdin
py -3 bin/llama_delegate.py --ask "what does parse() return on error?" --file src/utils.py
# Iterate in a multi-turn conversation (one history file per task)
py -3 bin/llama_delegate.py "make it simpler" --session task1.json
# Guaranteed-schema JSON output
py -3 bin/llama_delegate.py "extract the function names" --json-schema '{"type": "object"}'
# Usage report with estimated cloud-cost savings / health check
py -3 bin/llama_delegate.py --report --savings
py -3 bin/llama_delegate.py --health-only--file: pass paths, not content — the script loads files itself, so the cloud agent never reads them into its own context.--focus: with--file, inline only the region defining a symbol instead of the whole file. Recognized: Pythondef/class; JS/TSfunction/interface/type(also withexport); Rustfn/struct/enum/impl; Gotype. Not recognized: Go receiver methods (func (r *T) Name) and brace-delimitedclassbodies.--grep: with--file, inline only the lines matching a regex (case-insensitive) plus--grep-contextlines (default 3), numbered, with...between non-adjacent regions. Pure keyword lookup — no model call, cheaper than--focus. Falls back to the whole file when nothing matches.- Auto-summary fallback: files that overflow the token budget are replaced by a locally generated summary automatically.
- Summary cache: summaries are cached by content hash in
summary_cache/; unchanged files are never re-summarized. --patch: the model emits only SEARCH/REPLACE blocks, not whole files.- Self-fix loop:
--patch ... --test "<cmd>"runs the command after applying; on failure the model gets the error output, fixes the file and re-tests (up to--test-retries, default 3; the pre-patch file is restored if it never passes). Same verify→fix→retest loop an agent would drive, zero cloud tokens. Caveat: "tests pass" is not "the fix is good" — a small quantized model can occasionally patch its way to green, so spot-check the diff before trusting it unattended. - Text modes:
--triage,--review,--commit-msg,--summarize-stdinand--askgive the agent one-call, structured answers for test logs, diffs and repo questions — the raw log/diff never enters cloud context, only the short local answer does. - Response cache: identical requests (chat, patch, text modes) are
served from
response_cache/instead of the GPU — instant repeats, no usage logged. Bypass with--no-cache. - Honest output: every mode instructs the model to say so when it is
unsure or the context is insufficient instead of guessing, and to accept
corrective feedback and revise (works across
--sessionturns). - Session compaction: long
--sessionhistories are condensed locally. - Budget guard: exact
/tokenizecounting against a 70k prompt cap (override with$LLAMA_KIT_MAX_PROMPT_TOKENS; the legacy$COPILOT_PROVIDER_MAX_PROMPT_TOKENSstill works as a fallback).
| Technique | Cloud-context cost |
|---|---|
| Reading a 57 KB source file into the agent | ~13,000 tokens |
Same file via --file --focus <symbol> |
3–15% of that (1,700–8,700 chars) |
| Same file auto-summarized locally | ~1,500 tokens (cached forever) |
Prefix caching (--cache-prompt), 20k-token prefix |
18.0s → 2.75s (6.5x) |
| Delegated task itself | 0 cloud tokens |
Every routine task routed here converts cloud input+output tokens into free
local GPU time; --report --savings estimates the dollar value, broken down
per mode (sorted by savings) so you can see which delegations pay off most.
By default the estimate assumes $3/$15 per 1M input/output tokens. Price it against a real cloud model instead:
py -3 bin/llama_delegate.py --list-prices # show the table
py -3 bin/llama_delegate.py --report --savings --cloud-model sonnet-5
py -3 bin/llama_delegate.py --report --savings --cloud-model "bailian-intl/qwen3.8-max-tp"The table (in llama_kit/pricing.py) covers Claude Opus/Sonnet/Haiku/Fable,
GPT-5.6 sol/terra/luna, GPT-5.5(+pro), GPT-5 nano, Gemini 3.1 Pro / 3 Flash,
and Qwen3-Max/3.8-Max, as of 2026-08-30 — vendor prices move, so check
--list-prices notes or pass explicit --input-price/--output-price
(those always win over --cloud-model).
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | malformed model response / patch failed |
| 2 | bad input (empty prompt, missing file, bad schema) |
| 3 | PROMPT_TOO_LONG — prompt exceeds the safe budget |
| 4 | LOCAL_MODEL_UNAVAILABLE — server unreachable/autostart failed |
llama_kit/— the package:delegate.py(CLI),completion.py(request + slot lock + retry),summarize.py,patch.py,sessions.py,report.py,pricing.py,telemetry.py,client.py,tokens.py,config.pytests/— pytest suite (run:py -3 -m pytest tests -q), also wired to GitHub Actions (.github/workflows/test.yml)bin/llama_delegate.py,bin/usage_report.py— thin entry points (they only import and callllama_kit; all logic lives in the package)config.example.json— template; copy toconfig.jsonand editintegrations/qoder/,integrations/claude/,integrations/copilot/— optional wiring for Qoder CLI, Claude Code, and GitHub Copilot (see below)hooks/read_file_guard.py— optional Qoder hook: warns the agent when it Reads a file >50 KB and suggests the local summary path (seehooks/README.md)usage.jsonl,server.log,summary_cache/,response_cache/,config.json— runtime / machine-private data (gitignored)
The toolkit works standalone, but it can wire itself into Qoder CLI so your agent offloads routine work automatically. From a fresh clone, one command does the whole install:
git clone https://github.com/flyingriverhorse/llama-kit.git
cd llama-kit
powershell -ExecutionPolicy Bypass -File integrations\qoder\install.ps1 # Windowsgit clone https://github.com/flyingriverhorse/llama-kit.git
cd llama-kit
sh integrations/qoder/install.sh # Linux/macOSThe installer (1) copies the repo to ~/.qoder/skills/local/ so the
/local skill is live, (2) installs the local-gpu-offloader agent into
~/.qoder/agents/ with all <HOME> placeholders replaced, and (3) creates
config.json from the template. Afterwards: edit config.json (your
llama.cpp folder + model), restart Qoder CLI, done.
Step-by-step details, optional extras (delegation snippet for your own
skills, per-project AGENTS.local.md, the large-file guard hook), and
uninstall: integrations/qoder/README.md.
Your own machine-private files (real config.json, your projects'
AGENTS.local.md) must never be committed — they contain personal paths.
The toolkit is agent-agnostic; the same delegate CLI works from any coding agent that can run shell commands:
- Claude Code —
integrations/claude/: one-command installer (agent + skill into~/.claude/) plus aCLAUDE.mddelegation snippet. Seeintegrations/claude/README.md. - GitHub Copilot —
integrations/copilot/: a custom-agent template for.github/agents/and a delegation snippet for Copilot instructions. Seeintegrations/copilot/README.md.
- Start the server with
--cache-prompt: repeated prefixes (session history, shared system prompts) are then reused from the KV cache — measured ~6x faster second requests on a 20k-token prefix. - Thinking/reasoning is OFF by default (
enable_thinking: falsein the chat template); add--thinkfor complex generation. - Single slot (
-np 1) is enforced via a lock file: parallel callers queue. A lock left behind by a dead process (Ctrl-C, crash, timeout) is detected via its PID and removed automatically, so callers never queue behind a corpse. - Batch small related tasks into one call ("1) docstring for f, 2) rename x, 3) ...") — one round-trip and the shared prefix stays hot in the cache.
- Explore locally first: before an agent reads 3+ files or any file >50 KB
into cloud context,
--summarizethem (or use--file/--focus).
Full option list for the commands shown in Usage
(llama_delegate.py [prompt] [options]; reads stdin when no prompt):
| Option | Default | Purpose |
|---|---|---|
--url URL |
config / http://localhost:8080 |
llama-server base URL |
--system TEXT |
terse assistant prompt | system prompt |
--max-tokens N |
2048 | generation budget |
--ctx-limit N |
80000 | server context window (match -c) |
--max-prompt-tokens N |
env or 70000 | hard prompt cap |
--temperature T |
0.6 | sampling temperature |
--timeout S |
600 | request timeout |
--think |
off | enable reasoning/thinking |
--health-only |
— | health check and exit |
--no-autostart |
— | don't launch the server |
--summarize F... |
— | cached local summaries |
--file PATH (repeatable) |
— | load file into prompt locally |
--focus SYM (repeatable) |
— | with --file: only that symbol |
--grep PATTERN |
— | with --file: only matching lines + context (no model call) |
--grep-context N |
3 | context lines around each --grep match |
--patch FILE |
— | SEARCH/REPLACE edit mode |
--dry-run |
— | preview --patch result |
--test CMD |
— | with --patch: verify + self-fix until CMD passes |
--test-retries N |
3 | max self-fix rounds for --test |
--summarize-stdin |
— | text mode: dense summary of stdin text/log |
--triage |
— | text mode: FAILING/ERROR/LIKELY_CAUSE/NEXT from a log |
--review |
— | text mode: SUMMARY/RISKS/FOCUS review of a diff |
--commit-msg |
— | text mode: Conventional Commits message from a diff |
--ask Q |
— | text mode: question about stdin/--file contents |
--no-cache |
— | bypass the response cache |
--session PATH |
— | multi-turn history file |
--json-schema FILE|JSON |
— | schema-constrained output |
--chunk-tokens N |
12000 | summarize chunk size |
--report [--savings] |
— | usage report (+$ estimate) |
--cloud-model NAME |
— | price --savings at a real cloud model |
--input-price / --output-price |
3.0 / 15.0 | cloud $/1M for --savings (override) |
--list-prices |
— | print the known cloud-model price table |
Every request is checked against a safe prompt budget before it is sent:
budget = min(ctx_limit − max_tokens, max_prompt_tokens)
--ctx-limitis the server's context window — it must match the-cvalue in yourstart_command(default: both 80000).--max-tokensis the room reserved for the model's output; it is subtracted from the context automatically.--max-prompt-tokens(or$LLAMA_KIT_MAX_PROMPT_TOKENS) is an extra ceiling on top; the smaller of the two wins.
So raising the output allowance or running a smaller context window shrinks the allowed prompt automatically — nothing to compute by hand. Adjust to your setup:
| Your setup | What to pass | Effective prompt budget |
|---|---|---|
Defaults (-c 80000, output 2048) |
nothing | 70,000 |
| Long outputs (e.g. big files) | --max-tokens 8000 |
min(72000, cap) = 70,000 |
Small context server (-c 16000) |
--ctx-limit 16000 |
13,952 |
| Keep prompts extra-cheap | LLAMA_KIT_MAX_PROMPT_TOKENS=40000 |
40,000 |
Exact token counts come from the server's /tokenize endpoint; a prompt
over the budget is rejected up front (PROMPT_TOO_LONG, exit 3). If you hit
that, drop context (--focus, --summarize) rather than raising the caps —
or raise --ctx-limit and restart the server with a matching -c.
LOCAL_MODEL_UNAVAILABLE(exit 4) — autostart failed. Checkserver.log; verifyworkdir+start_commandinconfig.json; try the command manually. Use--no-autostartif you manage the server yourself.PROMPT_TOO_LONG(exit 3) — prompt over the safe budget (see Tuning the token budget). Drop context (--focus,--summarize), or raise--max-prompt-tokens/--ctx-limit(must match the server's-c).- Port already in use — another
llama-serverholds 8080. Point--url/config.jsonat it, or start yours on another port. - Windows:
pythonnot found — use thepy -3launcher (installed with the official Python installer). - Slow first request after server start — normal: model load + KV warmup.
Repeat requests with the same prefix are much faster with
--cache-prompt. PATCH_FAILED(exit 1) — a SEARCH block didn't match; nothing was written. Retry with clearer instructions, or add--think.
MIT licensed.