Fast local LLM inference CLI for Apple Silicon. 1.57x faster than Ollama, 58% less memory.
4
stars
372
commits
Swift
primary language
Aug 31, 2026
updated
A Mac-native LLM runtime that's also a coding agent.
One Swift + MLX binary — text, vision, and voice. No Python.
Most local-LLM stacks are one half of a pair:
Krill is both, in one binary. The same native Swift + MLX engine that serves tokens also runs a full agent loop — tools, file edits, web fetch, permissions — against the model already sitting in your RAM. Krill is local by default: the native path needs no second process or Python bridge and keeps model traffic on your Mac. Hosted model traffic leaves the machine only when you explicitly select OpenCode or Codex.
| Mode | Command | What you get |
|---|---|---|
| Chat | krill run <model> | Full-screen TUI (opens in agent mode; /chat for pure chat) — multimodal, streaming, on-device voice |
| Serve | krill serve | Drop-in OpenAI · Ollama · Anthropic API on :57455 |
| Agent | krill code <task> | Coding agent — bash, edits, glob/grep, web, deep research — on a local model, OpenCode free model, or Codex subscription |
| Phone / Web | krill serve → open /ui | The same agent from any browser or phone — sessions per repo, live tool calls, tap-to-approve. Ships inside the binary |
The agent isn't boxed into your filesystem. web_search ranks the open web — keyless out of the box (DuckDuckGo), or point it at Brave/Tavily (free-tier API key) or your own SearXNG for reliable results — and web_fetch reads any page as clean text — both SSRF-guarded and untrusted-framed against prompt injection — while /research <question> runs a multi-source deep-research pass (plan queries → fetch → summarize each source → synthesize a cited answer). A local model that browses, and cites its work.
And the inverse: krill launch claude (or codex, opencode, copilot, droid, hermes, pi) points an external harness at Krill's engine. Krill is the model for other agents, or the agent on its own model.
Whichever model you point at it, the agent's tool names are constrained while
the model samples them — so a model trained on some other harness's vocabulary
can't ask for a tool Krill doesn't offer and die on its first call. It's a
trigger-activated grammar: idle during prose, armed only inside a tool call, and
it costs no measurable decode time (docs/TOOL_NAME_RESOLUTION.md).
Underneath: a continuous batcher (~2× throughput under load), shared-prefix KV reuse (repeat prompts hit cache instead of re-prefilling — the agentic/RAG fast path), speculative decoding, and native vision (SigLIP2) + audio (USM Conformer). All Swift + MLX.
⚠️ Early release. Krill is young and still getting its polish — expect some rough edges, and pin a version if you need stability. Bug reports, ideas, and feedback are genuinely welcome → open an issue.
# Homebrew
brew tap srvsngh99/krill && brew install krill
# …or the one-line installer (Apple Silicon, no Homebrew needed)
curl -fsSL https://raw.githubusercontent.com/srvsngh99/Krill/main/install.sh | sh
The installer verifies the release archive against the SHA-256 digest
published by GitHub before extracting it. Set KRILL_VERSION to pin a release.
Updating: Homebrew installs update with brew upgrade krill; installer
builds update in place with krill update, which fetches the installer from
the target release tag (add --check to only see if a newer release is
available).
# Requires macOS 14+ (Apple Silicon, M1+), Swift 6.2+, and the Metal Toolchain
# xcodebuild -downloadComponent MetalToolchain
git clone https://github.com/srvsngh99/Krill.git && cd Krill
make release && make install # → /usr/local/bin/krill
krill pull gemma-4-e2b # text + image + audio, all native
krill run gemma-4-e2b # chat: full-screen TUI
krill run gemma-4-e2b "explain MLX in one line" # chat: one-shot
krill code "add a docstring to the top fn in main.swift" # agent: tools + edits
krill serve --model gemma-4-e2b # API server on :57455
krill run gemma-4-e2b "what's here?" --image ./photo.png # vision
krill run gemma-4-e2b "transcribe this" --audio ./clip.wav # audio
krill pull unlimited-ocr && krill run unlimited-ocr --image page.png "document parsing." # OCR
The local MLX path remains the default. Hosted providers are explicit and use the classic line renderer while Krill continues to own the tool loop and permission checks.
# OpenCode Zen is keyless. The catalog is read live and every `-free` model is
# available automatically; Ox Alpha is preferred while it remains advertised.
krill code --provider opencode --list-models
krill code --provider opencode "explain this repository"
krill code --provider opencode nemotron-3-ultra-free "review this change"
# Codex uses the official CLI's saved ChatGPT login. Krill never reads or
# copies the subscription credential and does not turn it into an API key.
codex login
krill code --provider codex "review this repository"
krill code --provider codex MODEL_ID "review this repository" # optional model
Omit the Codex model to keep the user's current/default subscription model.
Each user signs in with their own codex login; a shared API key is neither
required nor supported by this bridge. --base-url applies only to the
OpenCode-compatible provider; it is rejected for Codex.
OpenCode defaults to a 4096-token completion budget (use --max-tokens to
override it); the local MLX default remains 1024. Codex CLI controls its own
completion budget, so --max-tokens does not apply to that provider. A
response that reaches the hosted OpenCode budget reports a clear error with the
flag to increase it rather than silently treating a partial answer as complete.
Hosted reasoning models spend most of a turn before emitting any content, so OpenCode requests use a 300s ceiling rather than URLSession's 60s default, and transient failures (429/502/503/504, or a dropped connection) are retried twice with a short backoff before the error is surfaced. Free tiers return these routinely; a blip should not end an agent run.
The Codex bridge starts a fresh codex exec --ephemeral process for each agent
turn and sends that turn's full transcript to the CLI. It does not provide
cross-turn prompt caching, so usage and any applicable charges can grow with
long agent runs. Krill invokes the official CLI using its existing login; it
does not determine whether a particular account or plan is permitted for a
given workflow, so review the terms that apply to your account.
The default port 57455 is unique, so Krill coexists with Ollama on 11434; run krill serve --port 11434 for a literal drop-in.
📖 New to Krill? The User Guide is a single indexed, example-driven walkthrough of every feature — chat & TUI, multimodal (image / audio / OCR), agentic coding, the HTTP server, structured output, embeddings, web search, model management, and configuration.
Single-stream decode is at parity — both hit the MLX memory-bandwidth roof, and Krill makes no raw-decode-speed claim. Krill leads where real workloads live:
tool_choice tool calls. Ollama's MLX Gemma tag has none.Numbers track your hardware — reproduce them, don't trust a banner:
make bench-compare KRILL_MODEL=llama-3.2-1b OLLAMA_MODEL=llama3.2:1b
Full methodology and gates: docs/BENCHMARKS.md, docs/BENCHMARKING.md.
37 chat & multimodal models ship as one-word krill pull shortcuts (plus ~19 embedding / reranker models), spanning ~15 architecture families. Switch between installed models live in a chat with /model — the conversation carries over — or import any mlx-community repo and it joins the picker.
krill pull gemma-4-e2b # Gemma 4 — text + image + audio, all native (also: -e4b, -12b flagship)
krill pull qwen3.8-27b # Qwen 3.8 27B — hybrid linear-attention VLM, text + image (~16 GiB)
krill pull qwen3-14b # Qwen 3 (incl. MoE: qwen3-30b) — also Qwen 2.5: qwen2.5-7b
krill pull llama-3.2-3b # Llama 3.2 / 3.1 (also: llama-3.2-1b, llama-3.1-8b)
krill pull mistral-7b # Mistral 7B v0.3
krill pull gemma-2-9b # Gemma 2 9B
krill pull phi-4-mini # Phi-4 Mini
krill pull unlimited-ocr # native document/image OCR (DeepSeek-OCR)
krill pull mlx-community/Meta-Llama-3.1-8B-Instruct-4bit # …or any mlx-community repo
Native text also runs Phi, GLM-4, Mixtral, OLMoE, and DeepSeek-V2/V3, plus a ~15-family embedding/reranker stack. Vision serving adds LLaVA-1.5, Llama-3.2-Vision (mllama, multi-image), and Qwen2.5-VL.
Formats: not anything-goes — Krill is MLX-native. It runs MLX-format checkpoints (safetensors) in 4-bit, 8-bit, nvfp4 (mixed-precision 4-bit-float), or bf16/fp16 — GGUF is not supported. Any mlx-community model of a supported architecture loads as-is; convert other Hugging Face checkpoints with krill quantize <hf-path>.
| Command | Description |
|---|---|
krill run <model> [prompt] | Chat — interactive TUI or one-shot (/agent toggles agent mode) |
krill code [task] | Agent mode on local MLX; add --provider opencode or --provider codex for hosted backends |
krill serve | Start the HTTP server — OpenAI / Ollama / Anthropic APIs, agent sessions, and the web UI at /ui |
krill ui | One command for the phone app: serve in the background, print the phone link, open the UI (--install = always on) |
krill launch <agent> | Wire an external coding agent (Claude Code, Codex, …) to Krill |
krill pull / list / rm <model> | Manage models (download from HuggingFace) |
krill quantize <hf-path> | Convert an HF model to MLX |
krill bench <model> · krill version | Benchmark · version + system info |
Faster CLI: krill run reloads the model each call. Start a daemon once and subsequent calls auto-route to it — TTFT drops from seconds to milliseconds:
KRILL_KEEP_ALIVE=24h krill serve --model qwen2.5-3b &
krill run qwen2.5-3b "hi" # auto-routed → "(via daemon @ :57455)"
One server speaks three protocols — change the port in your client, nothing else:
/v1/chat/completions (SSE), /v1/completions, /v1/responses, /v1/models/api/chat, /api/generate, /api/tags/v1/messages (Claude SDK drop-in)from openai import OpenAI
client = OpenAI(base_url="http://localhost:57455/v1", api_key="not-used")
print(client.chat.completions.create(
model="llama-3.2-1b", messages=[{"role": "user", "content": "hi"}]
).choices[0].message.content)
OpenAI-family SDKs (openai, langchain-openai, llama-index) use …/v1; the Anthropic SDK takes the bare host (it appends its own /v1/messages). Request shapes and more SDKs: docs/SERVER_API.md, docs/CONNECT_CODING_AGENTS.md.
krill serve also serves a full agent UI at /ui — no app store, no extra
install, it ships inside the binary. Point the agent at any repo on your Mac
from your phone's browser: sessions, live tool-call transcript, and Deny /
Allow / Always approval cards for every mutating tool.
krill ui
That one command starts the server in the background (it keeps running after
you close the terminal), generates an API key on first run and saves it to
~/.krill/config.toml, prints the links, and opens the UI on the Mac:
>_ Krill UI
This Mac http://localhost:57455/ui
Same Wi-Fi http://192.168.1.23:57455/ui
Tailscale http://100.91.59.7:57455/ui
Phone link http://100.91.59.7:57455/ui#k=… (carries the key)
Stop krill ui --stop always-on at login: krill ui --install
krill ui --install registers the server as a login item —
it starts when you log in and restarts if it ever exits. krill ui --uninstall
removes it; krill ui --status reprints the links.Prefer to run it yourself? KRILL_API_KEY='…' krill serve --host 0.0.0.0 is the
same server (a non-loopback bind requires a key). Never port-forward it raw
to the internet — the agent runs tools on your Mac; keep it behind a VPN or an
authenticated tunnel. Full setup, endpoint contract, and development notes:
docs/AGENT_UI.md.
One Swift package, no Python. The engine and the agent harness share a process and the same loaded model.
Engine
KrillEngine — orchestration, continuous batcher, speculative decodingKrillCore — architectures (Llama, Qwen/MoE, Mistral, Gemma 4, Phi, GLM, DeepSeek …) + SigLIP2 vision + USM Conformer audioKrillCache — KV cache (fp16 / int8, prefix reuse) · KrillKernels — fused Metal shaders · KrillSampler · KrillGrammar — grammar-constrained decodeHarness
KrillHarness — agent loop, permissions, and tools (bash, read/write/edit, glob/grep, web fetch/search, dispatch, deep research)KrillAgent — hardware-aware operator / recommenderSurfaces
KrillServer — OpenAI/Ollama/Anthropic HTTP (swift-nio) · KrillCLI + KrillTUI — CLI and the full-screen chat/agent TUI · KrillRegistry — model store + HF puller · KrillTokenizerThe full-screen TUI (themes, slash commands, attachments, push-to-talk voice) has its own reference: docs/TUI.md.
~/.krill/config.toml, or environment variables:
| Var | Default | Purpose |
|---|---|---|
KRILL_DEFAULT_MODEL | — | Model used when none is named |
KRILL_PORT | 57455 | Server port |
KRILL_API_KEY | — | Require bearer authentication; needed for safe non-loopback serving |
KRILL_KV_CACHE_DTYPE | fp16 | KV cache precision (fp16 / int8) |
KRILL_PREFILL_CHUNK | 2048 | Prompt tokens per prefill pass — lets 32k+ contexts run without OOM (0 disables) |
KRILL_ROTATING_KV | 1 | Windowed KV for Gemma sliding layers — O(window) long-context decode (0 disables) |
KRILL_SEARCH_BACKEND | auto | Web-search backend: auto (keyless DuckDuckGo), brave, tavily, or searxng |
KRILL_BRAVE_API_KEY | — | API key for search_backend=brave (free tier available) |
KRILL_TAVILY_API_KEY | — | API key for search_backend=tavily (free tier available) |
web_search works with no setup via DuckDuckGo. For reliable, rate-limit-free
results, add a free-tier API key:
krill --config search_backend=brave # or: tavily
krill --config brave_api_key=YOUR_KEY # or export KRILL_BRAVE_API_KEY
Or point at a self-hosted SearXNG with search_backend=searxng + searxng_url.
See docs/decisions/0002-web-search-backends.md.
Sourav Singh / Sourav AI Labs · souravailabs.ai
MIT
372 commits
Swift
90.2%
Python
9.1%
Fast local LLM inference CLI for Apple Silicon. 1.57x faster than Ollama, 58% less memory.
4
stars
372
commits
Swift
primary language
Aug 31, 2026
updated
A Mac-native LLM runtime that's also a coding agent.
One Swift + MLX binary — text, vision, and voice. No Python.
Most local-LLM stacks are one half of a pair:
Krill is both, in one binary. The same native Swift + MLX engine that serves tokens also runs a full agent loop — tools, file edits, web fetch, permissions — against the model already sitting in your RAM. Krill is local by default: the native path needs no second process or Python bridge and keeps model traffic on your Mac. Hosted model traffic leaves the machine only when you explicitly select OpenCode or Codex.
| Mode | Command | What you get |
|---|---|---|
| Chat | krill run <model> | Full-screen TUI (opens in agent mode; /chat for pure chat) — multimodal, streaming, on-device voice |
| Serve | krill serve | Drop-in OpenAI · Ollama · Anthropic API on :57455 |
| Agent | krill code <task> | Coding agent — bash, edits, glob/grep, web, deep research — on a local model, OpenCode free model, or Codex subscription |
| Phone / Web | krill serve → open /ui | The same agent from any browser or phone — sessions per repo, live tool calls, tap-to-approve. Ships inside the binary |
The agent isn't boxed into your filesystem. web_search ranks the open web — keyless out of the box (DuckDuckGo), or point it at Brave/Tavily (free-tier API key) or your own SearXNG for reliable results — and web_fetch reads any page as clean text — both SSRF-guarded and untrusted-framed against prompt injection — while /research <question> runs a multi-source deep-research pass (plan queries → fetch → summarize each source → synthesize a cited answer). A local model that browses, and cites its work.
And the inverse: krill launch claude (or codex, opencode, copilot, droid, hermes, pi) points an external harness at Krill's engine. Krill is the model for other agents, or the agent on its own model.
Whichever model you point at it, the agent's tool names are constrained while
the model samples them — so a model trained on some other harness's vocabulary
can't ask for a tool Krill doesn't offer and die on its first call. It's a
trigger-activated grammar: idle during prose, armed only inside a tool call, and
it costs no measurable decode time (docs/TOOL_NAME_RESOLUTION.md).
Underneath: a continuous batcher (~2× throughput under load), shared-prefix KV reuse (repeat prompts hit cache instead of re-prefilling — the agentic/RAG fast path), speculative decoding, and native vision (SigLIP2) + audio (USM Conformer). All Swift + MLX.
⚠️ Early release. Krill is young and still getting its polish — expect some rough edges, and pin a version if you need stability. Bug reports, ideas, and feedback are genuinely welcome → open an issue.
# Homebrew
brew tap srvsngh99/krill && brew install krill
# …or the one-line installer (Apple Silicon, no Homebrew needed)
curl -fsSL https://raw.githubusercontent.com/srvsngh99/Krill/main/install.sh | sh
The installer verifies the release archive against the SHA-256 digest
published by GitHub before extracting it. Set KRILL_VERSION to pin a release.
Updating: Homebrew installs update with brew upgrade krill; installer
builds update in place with krill update, which fetches the installer from
the target release tag (add --check to only see if a newer release is
available).
# Requires macOS 14+ (Apple Silicon, M1+), Swift 6.2+, and the Metal Toolchain
# xcodebuild -downloadComponent MetalToolchain
git clone https://github.com/srvsngh99/Krill.git && cd Krill
make release && make install # → /usr/local/bin/krill
krill pull gemma-4-e2b # text + image + audio, all native
krill run gemma-4-e2b # chat: full-screen TUI
krill run gemma-4-e2b "explain MLX in one line" # chat: one-shot
krill code "add a docstring to the top fn in main.swift" # agent: tools + edits
krill serve --model gemma-4-e2b # API server on :57455
krill run gemma-4-e2b "what's here?" --image ./photo.png # vision
krill run gemma-4-e2b "transcribe this" --audio ./clip.wav # audio
krill pull unlimited-ocr && krill run unlimited-ocr --image page.png "document parsing." # OCR
The local MLX path remains the default. Hosted providers are explicit and use the classic line renderer while Krill continues to own the tool loop and permission checks.
# OpenCode Zen is keyless. The catalog is read live and every `-free` model is
# available automatically; Ox Alpha is preferred while it remains advertised.
krill code --provider opencode --list-models
krill code --provider opencode "explain this repository"
krill code --provider opencode nemotron-3-ultra-free "review this change"
# Codex uses the official CLI's saved ChatGPT login. Krill never reads or
# copies the subscription credential and does not turn it into an API key.
codex login
krill code --provider codex "review this repository"
krill code --provider codex MODEL_ID "review this repository" # optional model
Omit the Codex model to keep the user's current/default subscription model.
Each user signs in with their own codex login; a shared API key is neither
required nor supported by this bridge. --base-url applies only to the
OpenCode-compatible provider; it is rejected for Codex.
OpenCode defaults to a 4096-token completion budget (use --max-tokens to
override it); the local MLX default remains 1024. Codex CLI controls its own
completion budget, so --max-tokens does not apply to that provider. A
response that reaches the hosted OpenCode budget reports a clear error with the
flag to increase it rather than silently treating a partial answer as complete.
Hosted reasoning models spend most of a turn before emitting any content, so OpenCode requests use a 300s ceiling rather than URLSession's 60s default, and transient failures (429/502/503/504, or a dropped connection) are retried twice with a short backoff before the error is surfaced. Free tiers return these routinely; a blip should not end an agent run.
The Codex bridge starts a fresh codex exec --ephemeral process for each agent
turn and sends that turn's full transcript to the CLI. It does not provide
cross-turn prompt caching, so usage and any applicable charges can grow with
long agent runs. Krill invokes the official CLI using its existing login; it
does not determine whether a particular account or plan is permitted for a
given workflow, so review the terms that apply to your account.
The default port 57455 is unique, so Krill coexists with Ollama on 11434; run krill serve --port 11434 for a literal drop-in.
📖 New to Krill? The User Guide is a single indexed, example-driven walkthrough of every feature — chat & TUI, multimodal (image / audio / OCR), agentic coding, the HTTP server, structured output, embeddings, web search, model management, and configuration.
Single-stream decode is at parity — both hit the MLX memory-bandwidth roof, and Krill makes no raw-decode-speed claim. Krill leads where real workloads live:
tool_choice tool calls. Ollama's MLX Gemma tag has none.Numbers track your hardware — reproduce them, don't trust a banner:
make bench-compare KRILL_MODEL=llama-3.2-1b OLLAMA_MODEL=llama3.2:1b
Full methodology and gates: docs/BENCHMARKS.md, docs/BENCHMARKING.md.
37 chat & multimodal models ship as one-word krill pull shortcuts (plus ~19 embedding / reranker models), spanning ~15 architecture families. Switch between installed models live in a chat with /model — the conversation carries over — or import any mlx-community repo and it joins the picker.
krill pull gemma-4-e2b # Gemma 4 — text + image + audio, all native (also: -e4b, -12b flagship)
krill pull qwen3.8-27b # Qwen 3.8 27B — hybrid linear-attention VLM, text + image (~16 GiB)
krill pull qwen3-14b # Qwen 3 (incl. MoE: qwen3-30b) — also Qwen 2.5: qwen2.5-7b
krill pull llama-3.2-3b # Llama 3.2 / 3.1 (also: llama-3.2-1b, llama-3.1-8b)
krill pull mistral-7b # Mistral 7B v0.3
krill pull gemma-2-9b # Gemma 2 9B
krill pull phi-4-mini # Phi-4 Mini
krill pull unlimited-ocr # native document/image OCR (DeepSeek-OCR)
krill pull mlx-community/Meta-Llama-3.1-8B-Instruct-4bit # …or any mlx-community repo
Native text also runs Phi, GLM-4, Mixtral, OLMoE, and DeepSeek-V2/V3, plus a ~15-family embedding/reranker stack. Vision serving adds LLaVA-1.5, Llama-3.2-Vision (mllama, multi-image), and Qwen2.5-VL.
Formats: not anything-goes — Krill is MLX-native. It runs MLX-format checkpoints (safetensors) in 4-bit, 8-bit, nvfp4 (mixed-precision 4-bit-float), or bf16/fp16 — GGUF is not supported. Any mlx-community model of a supported architecture loads as-is; convert other Hugging Face checkpoints with krill quantize <hf-path>.
| Command | Description |
|---|---|
krill run <model> [prompt] | Chat — interactive TUI or one-shot (/agent toggles agent mode) |
krill code [task] | Agent mode on local MLX; add --provider opencode or --provider codex for hosted backends |
krill serve | Start the HTTP server — OpenAI / Ollama / Anthropic APIs, agent sessions, and the web UI at /ui |
krill ui | One command for the phone app: serve in the background, print the phone link, open the UI (--install = always on) |
krill launch <agent> | Wire an external coding agent (Claude Code, Codex, …) to Krill |
krill pull / list / rm <model> | Manage models (download from HuggingFace) |
krill quantize <hf-path> | Convert an HF model to MLX |
krill bench <model> · krill version | Benchmark · version + system info |
Faster CLI: krill run reloads the model each call. Start a daemon once and subsequent calls auto-route to it — TTFT drops from seconds to milliseconds:
KRILL_KEEP_ALIVE=24h krill serve --model qwen2.5-3b &
krill run qwen2.5-3b "hi" # auto-routed → "(via daemon @ :57455)"
One server speaks three protocols — change the port in your client, nothing else:
/v1/chat/completions (SSE), /v1/completions, /v1/responses, /v1/models/api/chat, /api/generate, /api/tags/v1/messages (Claude SDK drop-in)from openai import OpenAI
client = OpenAI(base_url="http://localhost:57455/v1", api_key="not-used")
print(client.chat.completions.create(
model="llama-3.2-1b", messages=[{"role": "user", "content": "hi"}]
).choices[0].message.content)
OpenAI-family SDKs (openai, langchain-openai, llama-index) use …/v1; the Anthropic SDK takes the bare host (it appends its own /v1/messages). Request shapes and more SDKs: docs/SERVER_API.md, docs/CONNECT_CODING_AGENTS.md.
krill serve also serves a full agent UI at /ui — no app store, no extra
install, it ships inside the binary. Point the agent at any repo on your Mac
from your phone's browser: sessions, live tool-call transcript, and Deny /
Allow / Always approval cards for every mutating tool.
krill ui
That one command starts the server in the background (it keeps running after
you close the terminal), generates an API key on first run and saves it to
~/.krill/config.toml, prints the links, and opens the UI on the Mac:
>_ Krill UI
This Mac http://localhost:57455/ui
Same Wi-Fi http://192.168.1.23:57455/ui
Tailscale http://100.91.59.7:57455/ui
Phone link http://100.91.59.7:57455/ui#k=… (carries the key)
Stop krill ui --stop always-on at login: krill ui --install
krill ui --install registers the server as a login item —
it starts when you log in and restarts if it ever exits. krill ui --uninstall
removes it; krill ui --status reprints the links.Prefer to run it yourself? KRILL_API_KEY='…' krill serve --host 0.0.0.0 is the
same server (a non-loopback bind requires a key). Never port-forward it raw
to the internet — the agent runs tools on your Mac; keep it behind a VPN or an
authenticated tunnel. Full setup, endpoint contract, and development notes:
docs/AGENT_UI.md.
One Swift package, no Python. The engine and the agent harness share a process and the same loaded model.
Engine
KrillEngine — orchestration, continuous batcher, speculative decodingKrillCore — architectures (Llama, Qwen/MoE, Mistral, Gemma 4, Phi, GLM, DeepSeek …) + SigLIP2 vision + USM Conformer audioKrillCache — KV cache (fp16 / int8, prefix reuse) · KrillKernels — fused Metal shaders · KrillSampler · KrillGrammar — grammar-constrained decodeHarness
KrillHarness — agent loop, permissions, and tools (bash, read/write/edit, glob/grep, web fetch/search, dispatch, deep research)KrillAgent — hardware-aware operator / recommenderSurfaces
KrillServer — OpenAI/Ollama/Anthropic HTTP (swift-nio) · KrillCLI + KrillTUI — CLI and the full-screen chat/agent TUI · KrillRegistry — model store + HF puller · KrillTokenizerThe full-screen TUI (themes, slash commands, attachments, push-to-talk voice) has its own reference: docs/TUI.md.
~/.krill/config.toml, or environment variables:
| Var | Default | Purpose |
|---|---|---|
KRILL_DEFAULT_MODEL | — | Model used when none is named |
KRILL_PORT | 57455 | Server port |
KRILL_API_KEY | — | Require bearer authentication; needed for safe non-loopback serving |
KRILL_KV_CACHE_DTYPE | fp16 | KV cache precision (fp16 / int8) |
KRILL_PREFILL_CHUNK | 2048 | Prompt tokens per prefill pass — lets 32k+ contexts run without OOM (0 disables) |
KRILL_ROTATING_KV | 1 | Windowed KV for Gemma sliding layers — O(window) long-context decode (0 disables) |
KRILL_SEARCH_BACKEND | auto | Web-search backend: auto (keyless DuckDuckGo), brave, tavily, or searxng |
KRILL_BRAVE_API_KEY | — | API key for search_backend=brave (free tier available) |
KRILL_TAVILY_API_KEY | — | API key for search_backend=tavily (free tier available) |
web_search works with no setup via DuckDuckGo. For reliable, rate-limit-free
results, add a free-tier API key:
krill --config search_backend=brave # or: tavily
krill --config brave_api_key=YOUR_KEY # or export KRILL_BRAVE_API_KEY
Or point at a self-hosted SearXNG with search_backend=searxng + searxng_url.
See docs/decisions/0002-web-search-backends.md.
Sourav Singh / Sourav AI Labs · souravailabs.ai
MIT
372 commits
Swift
90.2%
Python
9.1%