Juggler v1.0.0

The Agent Built
for Kimi & GLM

A lean, native Rust agentic CLI for Moonshot.ai (Kimi) and z.ai (Zhipu GLM) — with first-class Devscriptor code intelligence over MCP. Not another OpenAI-compatible shim: a harness that speaks each vendor's actual wire protocol.

Native Rust · 2024 editionPreserved Thinking74 Devscriptor MCP toolsOpen-weight models · run on-prem
terminal
# Point it at a repo and go
$ export ZAI_API_KEY=zai-...
$ juggler --provider glm -p "Explain this repo" --yes
# Or drop into the REPL
$ juggler --provider kimi --yes
Rationale

Frontier models, lowest-common-denominator plumbing

Kimi and GLM are among the strongest coding models available — and almost every agent talks to them through a generic OpenAI-compatible interface. That interface is a lossy adapter: it silently discards the capabilities these models were built around. Juggler was written to close that gap.

Reasoning is thrown away every turn

Generic client

A generic client drops the model’s reasoning content between turns — the model re-derives what it already worked out.

Juggler

Preserved Thinking replays each stored reasoning block back to the provider verbatim, which is exactly what both vendors require.

Reasoning effort is sent to models that reject it

Generic client

`reasoning_effort` is a GLM-5.2-and-newer parameter. Moonshot’s schema has no such property.

Juggler

Juggler routes it only to models that accept it, and never sends it to a Kimi model.

Temperature is injected where it does not exist

Generic client

The Kimi K2 request schemas have no `temperature` property at all — only the legacy `moonshot-v1-*` models do.

Juggler

Juggler deliberately omits it for K2, and clamps + sets `do_sample: false` for GLM when temperature ≤ 0.

Real tool schemas get rejected

Generic client

Moonshot’s validator is stricter than OpenAI’s. Realistic MCP tool schemas — with `$ref`s and `$defs` — bounce.

Juggler

Juggler normalizes every schema: dereferences `$ref`s, preserves circular refs, prunes orphaned definitions, repairs `enum`/`const` vs `type` conflicts.

The strategic argument

Open weights mean you can own the whole stack

Kimi and GLM are both released as open-weight models. That is not a footnote — it is the whole strategic case. The same flagship model you reach over the API can be downloaded and served on hardware you own, inside a network you control, with no third party in the path.

For a team that genuinely cannot send source code to an external provider, the economics are worth doing honestly: a one-time hardware purchase — on the order of a single senior engineer's annual salary — buys a permanently in-house, frontier-class coding model. No per-token billing, no rate limits, no data-processing agreement, and nothing leaving the building. Set against a recurring per-seat API spend, that capital cost stops looking exotic and starts looking like procurement.

Juggler is built for that end state. Point --base-url at your own OpenAI-compatible server and the agent runs against your self-hosted weights. Pair it with Devscriptor — which is already 100 % local, with no cloud backend — and every layer of the stack sits inside your perimeter: the model, the code index, and the agent that drives them.

The model
Open weights, self-hosted
The code index
Devscriptor — local SQLite
The agent
Juggler — a single binary
Signature feature

Preserved Thinking

Carry a turn's reasoning into the next one instead of discarding it. Juggler replays each stored reasoning block back to the provider verbatim — which is what both vendors require. The two vendors spell it differently, with inverted polarity. Juggler translates.

Kimi (Moonshot)GLM (Z.AI)
Wire fieldthinking.keepthinking.clear_thinking
Enabled"all"false
Disabledfield omittedtrue
Supported bykimi-k2.6 and newerevery thinking model
Default when unseton, whenever thinking is onthe endpoint decides

Why it matters: a reasoning model that loses its own reasoning every turn re-derives the same conclusions on the next one — burning tokens and latency to arrive back where it started. Precedence is --thinking-keep KIMI_MODEL_THINKING_KEEP thinking_keep in the config file → the model's own default. Models whose schema lacks the field never receive it.

Under the hood

What “provider-native” actually means

Not marketing. These are the concrete things lm-bridge does that a shared OpenAI-compatible client structurally cannot.

Version-aware context windows

Juggler carries a per-model context table (kimi-k2.6 and kimi-k2.7-code at 262,144; kimi-k2.5 and kimi-k2-0711-preview at 256,000) instead of one conservative default.

A new minor version has never lowered a model’s window, so an uncatalogued glm-5.3 inherits glm-5.2’s window rather than collapsing to a 128k default — which would make the agent compact its context far more often than it needs to.

Moonshot schema normalization

A dedicated pass rewrites JSON Schemas so Moonshot’s validator accepts them.

Dereferences local $ref pointers (#, #/$defs/X, #/definitions/X), detects and preserves circular references, drops definition buckets that are no longer referenced, injects missing type fields, and repairs conflicting enum/const vs. type.

Native Z.AI endpoints

Standalone Z.AI /web_search, /tools, and /reader HTTP resources, mirroring the official z.ai SDK — not bolted on through chat completions.

Juggler’s default GLM base URL is Z.AI’s Coding Plan endpoint, which preserves reasoning by default (the standard API endpoint does not). Leaving thinking_keep unset lets that endpoint default stand.

Kimi builtin_function & prompt caching

Kimi’s builtin_function tool type is passed through natively, and prompt_cache_key is set so Moonshot can reuse cached prefixes across turns.

Tool-call IDs are sanitized and deduplicated, and streaming tool-call deltas are routed in parallel so multiple concurrent calls assemble correctly.

Deep integration

Devscriptor, wired in on first run

Juggler auto-detects an installed Devscriptor and registers it as the devscriptor MCP server — 74 tools, zero configuration.

Discovery & startup

  1. 1$DEVSCRIPTOR_BIN — an explicit path
  2. 2$PATH
  3. 3Platform install directories (per-OS)
Started as devscriptor mcp with a 60 s startup timeout and a 180 s per-tool timeout. An explicit [[mcp_servers]] entry named devscriptor always wins over auto-detection. Run juggler doctor to confirm it connects.

A permission policy that fits

Without a policy, an agent would prompt on nearly every Devscriptor call — defeating the point of an indexed code-intelligence server. Juggler ships one tuned for it:

Prompts

lsp_arch_setup · rename_symbol · prune_context · start/stop/restart_server

Allowed for the session

Everything else — scan, analyze, search, navigate, context notes, watcher. Path sandboxing is enforced independently, so an allow rule can never escape allowed_paths.

Registered as dynamic tools. Devscriptor's 74 tools would swamp a tool table on their own. Juggler announces them as one-line summaries and lets the model pull in what it needs with select_tools — so the initial context stays small and the full toolkit is still one call away.

The harness

Scaffolding that earns its keep

A good model still needs somewhere good to run. agent-core is the turn loop, the scheduler, the context manager, and the guardrails.

Conflict-aware parallel tools

The scheduler builds a read/write/read-write tree over tool arguments and runs everything it can in parallel — without letting two writers collide on the same path.

Progressive tool disclosure

Large MCP servers do not flood the tool table. Dynamic tools are announced as one-line summaries; the model calls select_tools to load what it actually needs.

Two-stage context compaction

Proactive compaction fires at 90 % of the token budget; an emergency pass catches a real overflow, including GLM’s 1261 context-length error. Genuine user messages are protected with a head/tail split.

Repeated-call guard

Identical calls inside one step run once. A call repeated across steps draws an escalating reminder at streaks of 3, 5 and 8 — and the turn is stopped outright at 12.

Sub-agents & swarms

agent and agent_swarm delegate work. A headless run holds the turn open until sub-agents reach a terminal state and feeds their results back, instead of exiting and killing them.

Rule-based permissions

Three modes (default, accept_edits, bypass_permissions) plus ordered rules where the first match wins. Path sandboxing is enforced independently, so an allow rule can never escape allowed_paths.

Background work & scheduling

Background tasks outlive the turn that started them. task_list / task_output / task_stop manage them; cron_create schedules recurring work.

Three front-ends

Headless (-p) for scripting and CI, an interactive REPL, and an optional TUI behind a Cargo feature. Sessions persist as JSONL records and export to a ZIP archive.

Tools

26 built-in tools

What a fresh agent advertises before a single MCP server is attached. MCP tools are namespaced mcp__<server>__<tool>.

Filesystem

6
read_filewrite_fileedit_filelist_dirglobgrep

Execution

1
bash

Web

2
fetchweb_search

Planning

3
todo_listenter_plan_modeexit_plan_mode

Delegation

2
agentagent_swarm

Background work

3
task_listtask_outputtask_stop

Scheduling

3
cron_createcron_listcron_delete

Goals

2
create_goalget_goal

Interaction

2
ask_userask_user_question

Media

1
read_media

Tool disclosure

1
select_tools

update_goal and set_goal_budget are also registered but stay hidden until a goal is active. The whole table is pinned by a snapshot test — adding or renaming a tool fails the build until the documented list is updated.

Providers

Three providers, one binary

Override the model with --model and the endpoint with --base-url. Any other --provider value is rejected at startup.

--provider kimi

Moonshot.ai

Default model
kimi-k2-0711-preview
Default base URL
https://api.moonshot.cn/v1
API key
KIMI_API_KEY
--provider glm

z.ai (Zhipu)

Default model
glm-5.1
Default base URL
https://api.z.ai/api/coding/paas/v4
API key
ZAI_API_KEY
--provider openai

Any OpenAI-compatible endpoint

Default model
gpt-4o-mini
Default base URL
https://api.openai.com/v1
API key
OPENAI_API_KEY

Self-hosting? The openai provider speaks generic /chat/completions, so pointing --base-url at your own inference server runs Juggler entirely against weights you host yourself.

Configuration

Configure once, or not at all

Juggler reads ~/.config/juggler/config.toml or .juggler.toml in the current directory. CLI arguments override environment variables, which override file values.

provider = "glm"
model    = "glm-5.1"
base_url = "https://api.z.ai/api/coding/paas/v4"

# Sampling / budget
thinking         = true
thinking_keep    = false   # Preserved Thinking
reasoning_effort = "high"  # GLM-5.2 and newer only
max_tokens       = 8192

# Filesystem and context
allowed_paths                 = ["/srv/data"]
additional_dirs               = ["../sibling-repo"]
project_context_files         = ["NOTES.md"]
project_context_budget_tokens = 2048

permission_mode = "accept_edits"

# Devscriptor is auto-detected — no entry needed here.
[[mcp_servers]]
name = "http-tools"
url  = "http://localhost:8000/mcp"

# Permission policy; first matching rule wins.
[[permissions.rules]]
name   = "allow-reads"
tool   = "read_file"
action = "allow"
Permission modes
default · accept_edits · bypass_permissions
Reasoning effort
none → minimal → low → medium → high → xhigh → max
Subcommands
doctor · version · completions · export · tui
Free to install and use

Download Juggler 1.0.0

One universal binary per platform. No package managers, no build-from-source.

Better together

Juggler drives the model. Devscriptor gives it a map of your codebase. Install both and the agent starts with 74 code-intelligence tools already on the table.