quack
Any model.
Any provider.
No leaks.
A terminal coding agent that gets the best out of whatever model you point it at: llama.cpp on your desk, vLLM in your lab, an open-model API, or Claude and GPT.
It would be worth using if it phoned home. It doesn't.
Where to find it
$ curl -fsSL https:/ / github.com/ paulhovey/ quack/ releases/ latest/ download/ install.sh | sh Then run quack; it finds model servers on this machine or walks you
through adding one.
- Repairs messy tool calls Qwen3-XML, GLM, DeepSeek, Kimi and more
- Keeps prompt caches warm the system prompt never changes
Same model, two harnesses
The generic grinder
one harness for every modelsame tools,
for everyone
What comes out · pick one
_(o)> quack
a profile per model familyprompts and edit format
that suit the model
What comes out
Tool call printed as text
The model writes its tool call as Hermes or Qwen3-XML markup in the reply instead of a real call.
In a generic harness
The harness shows the markup to you as prose. Nothing runs, and the turn stalls or loops.
<tool_call>
{"name": "read", "arguments": {"path": "src/main.rs"}}
</tool_call>In quack
Calls printed as text in the Hermes, Qwen3-XML, GLM, DeepSeek or Kimi formats become real calls, and the raw markup never shows. Loose arguments are parsed and duplicate call ids are fixed.
✓ read src/main.rs · 212 lines
Seen in the wild
Field marks
Models and providers
- Local servers.
- llama.cpp, Ollama, vLLM, SGLang and LM Studio, found on this machine by
/setup. - Hosted services.
- 12 open-model APIs, from OpenRouter and DeepSeek to Kimi, Z.ai and Mistral, or any OpenAI-compatible URL.
- Claude and GPT.
- The Anthropic and OpenAI APIs with a key, or a ChatGPT plan through
quack login chatgpt. - Reasoning kept.
- Thinking survives tool calls and
/resume, sent back the way each API expects. - Switch any time.
/modelslists every model; switching keeps the history and approvals.- A planner model.
- Plan with a big model, carry it out with your usual one, and keep its cache warm.
Editing code
- Five edit formats.
- hashline, str_replace, apply_patch, search/replace blocks or whole files, chosen per model.
- A forgiving edit.
- Matches past stray whitespace, copied line numbers and smart quotes; keeps CRLF and BOMs.
- All or nothing.
- A multi-file change that fails partway rolls every file back.
- Undo and rewind.
/undothe last call, or/rewindthe conversation, the files, or both.- Code intelligence.
- Language servers for 11 languages, plus an
lsptool for definitions, references and hover. - Outlines.
indexoutlines a file or folder with tree-sitter;reada symbol by name.
Long tasks
- A live todo list.
- The model keeps a checklist and sees it at every step.
- Sub-agents.
explorescouts the repo in its own context and hands back paths and line ranges.- Loop guards.
- Repeated calls, edit-test-edit cycles and empty replies are caught.
- Changed-file reminders.
- The model is told which files it has touched, without rewriting history.
- Small windows.
- Old reads and outputs are pruned first; compaction keeps your request word for word.
- Sessions.
- Saved as they happen, crash-proof, and resumed with exactly the same context.
Safety
- Sandboxed shell.
- Commands write only in the workspace and have no network: Landlock + seccomp, or Seatbelt.
- Five permission modes.
- From read-only to yolo, with allow and deny rules over a floor you can’t remove.
- Commands parsed.
- In
git status && rm -rf xthermstill asks, even inside subshells and heredocs. - Project trust.
- A cloned repo’s
.quack/runs nothing until you trust it.
Making it yours
- MCP.
- Local and remote servers, deferred tool search, prompts as slash commands, forms and sampling.
- Hooks.
- Programs in any language on seven agent events; they can add context, block or rewrite calls.
- Skills and commands.
- SKILL.md skills, and any markdown file in
commands/becomes a slash command. - Your agent files.
- Reads AGENTS.md, CLAUDE.md, GEMINI.md,
.cursorrulesand Copilot instructions. - Memory.
- Notes per project and global, with approval before one is saved.
- Your own queries.
- Drop in
tags.scmorhighlights.scmto outline or colour a framework’s macros.
Everywhere
- Three systems.
- Linux, macOS and Windows on x64 and ARM64; PowerShell and Job Objects on Windows.
- Starts at once.
- The first frame draws in about <10 ms on Linux.
- Headless.
quack exec "…"runs one turn for scripts and CI.- Sees itself.
/contextand/statschart tokens, cache hits, cost and time.- Over SSH.
- Mouse selection and
/copygo through the terminal (OSC 52).
Measured, not guessed
quack eval runs a task suite against any model and profile and counts passes, steps,
bad calls, failed edits, tokens and cost. A family profile is switched on only when it clearly beats generic.| Date | Run | Result |
|---|---|---|
| 2026-10-21 | mistral-large-4, vibe vs generic, one hard pass | 14/14 each · 0 vs 12 bad calls · 1 vs 23 failed edits · $0.94 vs $1.70 |
| 2026-10-20 | glm-5.3-flash, zcode vs generic, hard suite ×3 | 37/42 vs 35/42 · 482 vs 539 steps · half the tool errors |
| 2026-10-20 | deepseek-v4.1-flash, dsh vs generic, hard suite ×3 | 42/42 each · 367 vs 424 steps · $0.36 vs $0.45 |
| 2026-10-19 | Per-session context moved out of the system prompt | Uncached prompt tokens down 45% on deepseek-v4.1-flash |
| 2026-10-19 | 8 models × 2 profiles, 21 small tasks (Charm Hyper) | All 21/21, no unparsable calls, $2.42 for the lot |
From the roadmap. Results files are in evals/results/.
Why the harness matters
FrontierHarness Eval held one model, Kimi K3, fixed across 30 tasks and changed only the harness. Pass rates ran from 50% to 67%, and the median cost of a task from $1.05 to $18.34.
quack hasn’t been run on it yet. When it has, the result goes here, whatever it is.
frontierharness.orgThe numbers behind the chart
| Harness | Pass rate | Median cost | Median cache hit |
|---|---|---|---|
| Codex | 66.7% | $3.47 | 88.0% |
| DSH Creator | 63.3% | $3.28 | 84.3% |
| Claude Code | 63.3% | $18.34 | 67.8% |
| Pi | 60.0% | $2.43 | 79.4% |
| DSH PTC | 60.0% | $4.58 | 87.2% |
| DSH Standard | 60.0% | $3.46 | 86.5% |
| Oh My Pi | 56.7% | $4.75 | 82.2% |
| Kimi Code | 56.7% | $3.65 | 88.0% |
| DSH Minimal | 56.7% | $4.72 | 84.6% |
| Exo Harness | 53.3% | $1.05 | 70.3% |
| OpenCode | 50.0% | $3.24 | 78.4% |
| Hermes | 50.0% | $2.90 | 85.9% |
For teams rolling it out
- Nothing built in that reaches out
- Every provider and MCP server is a small TOML file. Delete one and that capability is gone; a test checks startup stays clean for every default file. Only the core prompt and sub-agents are compiled in.
- Hosts you allow
- On top of contacting only what’s configured,
[policy.providers] hostsand[policy.mcp] hostsnarrow where providers and MCP servers may point, andquack doctorlists every host it can reach. - Settings you can lock
- Config layers from system to user, project, environment and command line. An administrator’s locks hold in
/config, andquack config show --originsays where each value came from. - Hooks users can’t remove
- Hooks in the system config folder are enforced: block a tool call, add context, or check a prompt, in any language.
- Ship your own files
quack-pluckedis the duck without its feathers: the whole agent minus the hosted-service providers, for teams with their own model server. The Config plate below walks through it.- Apache-2.0, few crates
- Every dependency is counted per OS before it’s added. The keyring adds no crates on Linux.
providers.d/lab.toml
base_url = "http://gpu-01.lab:8000/v1"
/etc/quack/config.toml
[policy.providers] hosts = ["gpu-01.lab"]
Your server. Nothing else.
quack-plucked, write two TOML files for https://<internal-server>:8000/v1, and you have the whole harness, with that
server as the only host it will ever contact.Install the plucked duck
The whole agent (prompts, sub-agents, MCP, ACP, language servers) minus the hosted-service providers, so nothing in it points off the machine. Offline, use
--archive, or the.deband.rpmpackages.shell
$ curl -fsSL https://github.com/paulhovey/quack/releases/latest/download/install.sh \ | sh -s -- --pluckedDescribe your server
Anything OpenAI-compatible: vLLM, SGLang, llama.cpp.
base_urlis the only required line; leave outmodelsand they’re listed from the server.providers.d/corp.toml
# /etc/quack/providers.d/corp.toml name = "Corp LLM" base_url = "https://llm.internal.example:8000/v1" api_key = { env = "CORP_LLM_KEY" } # leave out if no key models = [ { id = "qwen3-coder-480b", alias = "coder" }, { id = "qwen3-coder-30b", alias = "fast" }, ]
Lock it down
The system layer’s policy holds against user files, a repo’s
.quack/, environment variables and the command line.config.toml
# /etc/quack/config.toml [model] default = "corp/coder" small = "corp/fast" [network] offline = true [sandbox] mode = "workspace-write" # commands: no network [permissions] deny = ["shell:curl *", "shell:wget *"] [policy] locked = [ "model.default", "network", "sandbox.mode", "permissions.deny", ] max_permission_mode = "full-auto" # no yolo project_config = "trusted-only" [policy.providers] allowed = ["corp"] hosts = ["llm.internal.example"] [policy.mcp] hosts = ["*.internal.example"]
Check it
There’s nothing else to install.
quack doctormakes no model call; a user’s provider pointing elsewhere shows as blocked, and the only host listed is yours.terminal
$ quack doctor ok defaults /usr/share/quack/defaults warn providers 1 of 2 usable ok corp 2 declared models warn rogue not allowed by policy ok model corp/coder ok agents explore (on corp/fast), general ok sandbox workspace-write · Landlock + seccomp info network llm.internal.example · policy allows only llm.internal.example, *.internal.example
What’s guaranteed
- Only what the files name
- No telemetry, update checks or model downloads. A recording-proxy test and a CI run in a loopback-only network namespace check every build.
- Hosts are a policy, not a hope
- With
[policy.providers] hostsset, a provider pointing anywhere else doesn’t load, whoever wrote it: a user, a project or a bundle. - Locks hold everywhere
- User files, a repo’s
.quack/, environment variables,-cand/configcan’t change a locked key.QUACK_SYSTEM_DIRis ignored while the real system folder holds a policy. - Commands stay offline too
- The model’s shell commands run in the OS sandbox with no network on Linux and macOS. Windows has no sandbox yet, so there,
denyrules are the only control on commands.
Where it lives
Each layer overrides the one before. Every layer’s folder has the same shape, one file per item, and a file with
the same name in a higher layer replaces the lower one. quack config paths prints the
folders for this machine.
| Layer | Where | Notes |
|---|---|---|
| Defaults bundle | share/quack/defaults/ beside the binary, or QUACK_DEFAULTS_DIR | quack-plucked leaves out hosted services |
| System | /etc/quack/ · /Library/Application Support/quack/ · %ProgramData%\quack\ | The only layer whose [policy] counts |
| User | ~/.config/quack/ · %APPDATA%\quack\ | Your own files |
| Project | .quack/ at the repository root | Loads only once you trust the repo |
| Environment | QUACK_MODEL | Picks the model, like -m |
| Command line | -m, --profile, --permission-mode, -c key=value | This run only |
any layer’s folder
config.toml settings providers.d/*.toml model servers and services mcp.d/*.toml MCP servers lsp.d/*.toml language servers hooks.d/*.toml programs that run on agent events agents.d/*.toml sub-agents for the task tool profiles.d/<id>/ prompts and tool shapes per model family commands/*.md your slash commands skills/<name>/ SKILL.md skills bundles/<name>/ groups of the above AGENTS.md instructions for every project
Every option
Any subset works; everything left out keeps its default. quack config check validates
every file against its JSON schema, /config edits settings in the UI, and the README has the full list.
Models config.toml [model]
default""- Model to start with:
<provider>/<model>or<provider>/<alias> small""- Titles, summaries and the explore sub-agent. Empty:
default planner""- Writes the plan in plan mode; your usual model carries it out
remember_lasttrue- Start with the model you last switched to
profile""- One profile for every model, e.g.
genericorqwen-code
Permissions config.toml [permissions]
mode"ask"read-only,ask,auto-edit,full-auto(sandbox and deny rules still apply) oryoloallow[]- Rules that run without asking:
shell:cargo test*,edit:src/**,mcp:github/get_* ask[]- Rules that always ask, even in
full-auto deny[]- Rules that never run, in any mode. A built-in deny list always applies too
Sandbox config.toml [sandbox]
mode"auto"auto,workspace-write(no network),workspace-write-net,read-onlyoroff. A mode you set fails closedwritable[]- More folders commands may write to, e.g.
["~/.cargo"]
Network config.toml [network]
offlinefalse- Remote MCP servers must be on this machine or in
egress_allow egress_allow[]- Host globs allowed while offline
proxy""- Proxy for model requests. Empty:
HTTPS_PROXYor the system’s ca_bundle""- PEM file of extra root certificates, for an internal CA
Policy config.toml [policy], system layer only
locked[]- Dotted keys no other layer can change; a table locks all of it
max_permission_modeunset- The most permissive mode allowed,
--yoloincluded project_config"trusted-only"trusted-only,neveroralways: whether a repo’s.quack/loadsproviders.allowed[]- Provider id globs that may load. Empty: all
providers.hosts[]- Host globs a provider’s
base_urlmust match. Empty: any mcp.allowed[]- MCP server id globs that may load
mcp.hosts[]- Host globs a remote MCP server’s
urlmust match
Context config.toml [context]
windowunset- Use at most this many tokens of the model’s window
budget_ratio0.85- Share of the window quack plans to use
compaction_threshold0.80- Share of the budget at which pruning, then compaction, starts
cache_strategy"auto"autoorpreservekeep the prompt cache warm;aggressiveprunes every request
Tools config.toml [tools]
edit_format"auto"str_replace,hashline,apply_patch,search_replace_blocksorwhole_fileshell"auto"bash,zsh,pwsh,powershell,cmd, or a pathdefault_timeout_secs120- When a shell command’s process tree is killed
read_outline_tokens2000- Larger source files are read as an outline first.
0: off
Interface config.toml [ui]
theme"auto"darkorlightshow_reasoning"collapsed"collapsed,expandedorhiddenstartup_panel"auto"auto,alwaysorneverasciifalse- ASCII instead of box-drawing glyphs
mousetruefalseleaves the mouse to the terminalreduced_motionfalse- Static indicators instead of spinners
terminal_titletrue- Window title shows the duck and the session title.
false: leave it alone
Instructions, skills, memory, sessions config.toml
instructions.files["AGENTS.md"]- Instruction file names, in order of preference
instructions.other_agentstrue- Read CLAUDE.md, GEMINI.md,
.cursorruleswhere there’s no AGENTS.md instructions.max_bytes32768- Cap on each instruction file
skills.compat_paths[]- More skill folders, e.g.
.claude/skills skills.disabled[]- Skill names to skip
memory.path""- Where notes live, e.g. a synced folder
memory.project_scope"data-dir"repokeeps project notes in.quack/memorymemory.writes"auto"askmakes each note ask firstmemory.nudgetrue- Remind the model to save lasting preferences
sessions.path""- Where sessions are saved
defaults.dir""- The defaults bundle’s location;
"none"turns it off
A provider providers.d/<id>.toml
base_urlrequired- The API root, e.g.
https://llm.internal.example:8000/v1 api"openai-chat"openai-chat,openai-responses,anthropic-messagesorollamaapi_keynone- A secret:
{ env = … },{ file = … },{ cmd = […] }or{ keyring = … } models[]- Ids or tables. Empty: listed from the server
headers{}- Extra headers; values may be secrets
extra_body{}- Merged into every request
tls.ca_filenone- An extra CA for this server
tls.client_cert / client_keynone- Mutual TLS
http.timeout_idle_secs300- How long the stream may go quiet
http.max_retries3- Retries, honouring
Retry-After http.proxy""- A proxy for this provider only
A model models = [{ id = …, … }]
aliasnone- A short name:
corp/coder context_window / max_outputfrom the server- Token limits
profile"auto"- A profile id, or
autoto pick by its[match]globs visionfalse- Offer images to the model
tool_calling.mode"native"native,textorgrammar(schema-guided decoding)tool_calling.text_format"auto"hermes,qwen3-xml,glm,json-block,deepseekorkimireasoning.effort""- e.g.
low,medium,high samplingfrom the profiletemperature,top_p,top_k,min_p,repetition_penaltycostfrom the server- Dollars per million tokens, for
/stats
An MCP server mcp.d/<id>.toml
command / args- A local server, over stdio
url- A remote streamable HTTP server, instead
headers / env{}- Values may be secrets
sandboxfalse- Run a local server in the OS sandbox
tools.allow / deny[]- Tool name globs to offer or hide
tools.auto_approve[]- Tool name globs that run without asking
A language server lsp.d/<id>.toml
command / argsrequired- Used only when it’s on
PATH; nothing is installed extensionsrequired- File extensions it covers, without the dot
root_markers[]- Files that mark a project root
settings{}- Answers to
workspace/configuration diagnostics.min_severity"warning"error,warning,infoorhint
A hook hooks.d/<id>.toml
eventrequiredsession_start,user_prompt,pre_tool,post_tool,turn_end,session_end,pre_compactcommandrequired- Program and arguments;
{dir}is the file’s folder,{python}the Python onPATH match{}toolandpatternglobs for tool events, apromptregex for promptstimeout_secs10- How long it may run
on_error"warn"warn,allowordeny
A sub-agent agents.d/<id>.toml
descriptionrequired- What it’s for; the model reads it to choose
prompt""- Added to the system prompt for its run
toolsall- Tool names it may use
read_onlyfalse- Change nothing; may run in plan mode and in parallel
modelthe caller’ssmallor<provider>/<model>max_stepsnone- Model calls before it reports
Where to find it
quack.$ curl -fsSL https:/ / github.com/ paulhovey/ quack/ releases/ latest/ download/ install.sh | sh - Plucked: the duck without its feathers. The whole agent, with MCP, ACP, profiles and sub-agents, minus the hosted-service providers, for teams with their own model server.
--binary-onlyupdates just the binary. - Options:
--prefix,--version,--archive FILEfor offline installs, and--uninstall. - Archives for every platform are on the releases page.
In development and usable day to day. Not there yet: sandboxing on Windows, /fork --worktree, config auto-reload and MCP
OAuth.