kiwimatecoder
An agentic AI coding assistant for your terminal. Run one command and drop into an interactive session that can read, edit, and run code in your project — across the model provider of your choice. Bring your own API key.
Installation
pip install -e .
For a regular (non-editable) install:
pip install .
Installation options
Install script (no clone needed; installs from GitHub):
curl -fsSL https://raw.githubusercontent.com/Kyle8933/kiwimatecoder/main/scripts/install.sh | sh
The script checks for Python >= 3.10, prefers pipx when available (falling
back to pip install --user), verifies kiwimatecoder --version, and prints
PATH guidance when the console script is not yet visible. Append -s <ref> to
install a tag, branch, or commit, or set KIWIMATECODER_REF.
Docker:
docker build -t kiwimatecoder .
docker run --rm -it -v "$PWD:/workspace" -e OPENROUTER_API_KEY kiwimatecoder
docker run --rm -v "$PWD:/workspace" -e OPENROUTER_API_KEY kiwimatecoder \
-p "Summarize this repository" --model anthropic/claude-sonnet-5
The image is python:3.12-slim, installs the package, and runs as the
non-root kiwimate user with /workspace as the working directory. A fresh
container has no saved config, so no model is chosen: pass --model (see
Choosing a model).
Homebrew: packaging/homebrew/kiwimatecoder.rb is a virtualenv formula
template pinned to a git tag. It is not published to a tap yet; fill in the
tag revision and generate the resource blocks as described in the file, then
install with brew install --build-from-source ./packaging/homebrew/kiwimatecoder.rb.
Quick start
Add an API key for at least one provider, then launch the interactive session:
kiwimatecoder setup
kiwimatecoder
kiwimatecoder setup walks you through choosing a provider, saving its API
key, and choosing the model to use with it. There are no default models: after
the key is saved, setup shows the provider's model list (plus Type a model
id… for anything unlisted), and your pick is remembered for that provider.
You can also pass the arguments directly:
kiwimatecoder setup --provider openrouter
kiwimatecoder setup --provider openai --key sk-... --model gpt-5.6-sol # non-interactive
Without a terminal (or if you cancel the picker) and no earlier choice, setup
prints No model chosen yet (a local server instead uses the first model it
lists); the REPL then asks for a model when it starts, or you can set one later
with kiwimatecoder config model set <id>. At launch the REPL also asks about
any fallback provider on the roster that has no model (failover skips those),
and kiwimatecoder doctor warns about them.
Running kiwimatecoder with no arguments opens the interactive REPL. It keeps
running until you exit. Type a request in plain language and KiwiMateCoder will
read files, search the codebase, propose edits, and run commands to carry it
out. For larger or ambiguous tasks, it starts with a short plan and gives you a
few concrete options so you can choose the scope and tradeoffs before it
proceeds.
kiwi (openrouter:anthropic/claude-sonnet-5 · ask) › add a docstring to main.py
- Ctrl-C cancels the current turn and returns you to the prompt; whatever the model had already streamed is kept in the conversation so you can continue from it.
- Ctrl-D exits the session.
- While the agent is working you can type ahead: press Enter to send a steering
message and the model picks it up on its next step, or type a slash command
(e.g.
/undo) and it runs as soon as the turn finishes. Ctrl-C during the turn cancels it. - Your prompt history is saved; the up-arrow recalls commands from previous sessions.
- Every session is auto-saved when you exit. Pick it back up with
kiwimatecoder --continue(same as--resume last), or from inside the REPL with/load last. - Type
/to open the slash-command menu. It filters as you keep typing. - Run
/model,/provider, or/modewithout an argument to open a keyboard-driven selector./provideris a checklist: check every provider you want on the failover roster. The first checked provider is the primary; the rest are tried in order if the primary fails. Experimental providers (currently KiwiMate) appear in their own Experimental box at the top of the list. After you confirm, you choose a model for every provider on the roster that does not have one yet./provider <id>replaces the roster with that single provider (and asks for its model if none is chosen). Arrow keys move, Enter selects, and Ctrl-C returns to the prompt without changing anything. - Opening
/modelchecks the provider for models released since you last looked, and drops any it has retired./model refreshforces the check. The model you pick is saved as that provider's model for the next session. Each provider remembers its own model, so switching the primary with/provideruses the model chosen for the new primary instead of carrying a vendor-specific id across providers./config model resetforgets the choice: pick another with/model(local servers fall back to the first model they list). /model search <term>searches the provider's full catalog by name and opens the selector on the matches — useful when a model is older than the newest few that/modellists.- Use
/mode planwhen you only want investigation and options, with no edits or shell commands.
Permission modes
The agent can edit files and run shell commands. A permission mode controls how much
it can do without asking, and you can switch it at any time with /mode:
| Mode | Behavior |
|---|---|
ask (default) |
Reads run freely; every file write/edit or shell command shows a preview/diff and waits for your approval. |
auto-accept |
Actions run without prompting. |
plan |
Read-only: the agent can inspect and explain, but cannot write or run anything. |
At an approval prompt, answer a (always) to approve that tool for the rest of
the session and future sessions. Persisted approvals survive restarts and
provider switches; manage them with /config permissions or
config permissions list|remove|clear. When a diff spans multiple hunks, answer
h to choose which hunks to apply (e.g. 1,3, 1-2, all, or none).
Every mutating action is checkpointed before it runs. Restore the last change
with /undo, rewind several steps with /undo 3, and list them with
/checkpoints.
Reads, writes, edits, listings and searches are sandboxed to the workspace root (via symlink-aware path resolution). run_bash commands execute with the workspace root as their cwd but are otherwise unrestricted (subject to approval/mode); use them for git, tests, builds, etc.
Command rules
Auto-approve trusted commands and hard-block dangerous ones with regex rules
(deny rules block even in auto-accept mode):
/config commands allow ^pytest\b
/config commands deny rm\s+-rf
/config commands list
Dry run and trusted workspace
/dry-run previews every mutating tool call (diffs and shell commands) without
executing anything or prompting. /config trust on lets read-only tools read
paths outside the workspace root; writes stay sandboxed.
Slash commands
| Command | Description |
|---|---|
/help |
Show available commands. |
/exit, /quit |
Leave the session. |
/clear |
Clear the conversation history. |
/model [name|refresh|list|search <term>] |
Interactively choose a model (the list is refreshed from the provider), set one by name, refresh/show the list, or search the full catalog by name. The choice is remembered for that provider. |
/provider [id] |
Choose a failover roster (checklist; experimental providers sit in their own box at the top), or replace it with one provider by id. Asks for a model for each provider that has none. |
/mode [ask|auto-accept|plan] |
Interactively choose, or directly set, the permission mode. |
/dry-run [on|off|toggle] |
Preview mutating actions without running them. |
/undo [count], /checkpoints |
Restore files changed by recent tools, or list checkpoints. |
/todos |
Show the agent's task list. |
/templates |
List custom prompt templates discovered in the workspace and user command directories. |
/compact [budget] |
Trim older history to fit a token budget. |
/save, /load, /sessions, /fork [name], /export [path] |
Save, resume, branch, or export sessions as Markdown. |
/share [gist] [--include-tool-output], /share import <path> [--name NAME] |
Share a redacted session bundle as a local file or a secret GitHub gist, or import one as a saved session. |
/sync [status|push|pull] |
Show or sync saved sessions across machines through a shared folder (opt-in). |
/tools |
List available tools. |
/files |
List files changed this session. |
/context [list|add|remove|clear] |
Pin files to include as context on every turn. |
/image model [list|refresh|search <term>|<id>], /image [--size WxH] [--model id] <prompt> |
Generate an image with the configured media provider and attach it to your next message (opt-in; see Image and video generation). |
/video model [list|refresh|search <term>|<id>], /video [--duration s] [--size 720p] [--model id] [--image path] <prompt>, /video resume <job-id> |
Generate a short video (billed per second; takes minutes), or fetch a job that was still rendering. |
/media [list [count]|provider [id]] |
Show whether image and video generation are ready, list recently generated files, or switch the media provider. |
/memory [list|add|add-user|clear] |
Show or edit persistent project and user memory. |
/index [status|build|clear] |
Show, refresh, or delete the local codebase index used by semantic search. |
/jobs [list|show <id>|cancel <id>|tick|run <prompt>] |
List or manage detached background agent jobs; tick starts due scheduled runs. |
/config |
Show or change providers, keys, models, filters, permissions, command rules, sampling, styles, themes, output modes, accessibility, verify, and budgets. |
/mcp [list|reload] |
List configured MCP servers, their status, and registered tools; reload reconnects every server. |
/cost |
Show token usage, context gauge, and estimated USD cost for this session (per-model pricing). |
/doctor |
Run environment, config, provider, and workspace diagnostics. |
Examples:
/context add README.md kiwimatecoder/*.py
/undo 2
/export review.md
/fork experiment
Config examples:
/config
/config provider add local "Local Models" http://localhost:1234/v1 local-code LOCAL_API_KEY
/config provider edit local name="Local Models 2" model=local-fast
/config key set local <YOUR_KEY>
/config provider use local
/config model set anthropic/claude-sonnet-5 openrouter
/config model reset openrouter
/config models allow local-code local-fast
/config models deny noisy-model
/config models refresh
/config mode set plan
/config permissions list
/config permissions remove run_bash
/config commands allow ^pytest\b
/config commands deny rm\s+-rf
/config sampling set temperature=0.2 max_tokens=4096
/config sampling reset
/config style set concise
/config ui theme ocean
/config ui output compact
/config ui ascii on
/config prompt set "Prefer functional style; never use classes."
/config prompt clear
/config verify set "pytest -q"
/config budget tokens 500000
/config budget cost 5.00
/config trust on
/config remote host devbox
/config remote user kiwi
/config remote workspace /srv/app
/config remote enable on
/config browser enable on
/config browser headless off
/config browser timeout 20000
/config provider remove local
Running bare /config opens an interactive menu. Picking an entry lets you
change that setting: toggles and fixed choices (theme, locale, log level, …) are
picked from a list, free-form values (a proxy URL, an image size, a regex) are
typed, and each list shows the current value. Sections with several independent
settings, such as Media or UI, return to their list after each change
until you pick Done (Ctrl-C also leaves; at a typed prompt, Ctrl-C or an
empty line cancels just that entry). Keys works the same way: choose a
provider, then set (type a new key, which is not shown as you type) or remove
it. Only Show and help just print. Every entry also works as a typed
command as shown above, and /config key set / /config key list always show
which file or environment variable the active key comes from.
Tools
The assistant has these capabilities, all scoped to the workspace:
read_file,list_dir,search(grep + glob + semantic) — read-only, always allowed; batches of read-only calls run in parallel.view_image— attach a workspace image (.png,.jpg,.jpeg,.gif,.webp) so a vision-capable model can see it (see below).generate_image,generate_video— create an image or a short video through the configured media provider and save it under.kiwimatecoder/media/(opt-in and approval-gated because they cost money; see below).write_file,edit_file— create/modify files (approval-gated; each is checkpointed first so/undocan restore it).run_bash— run shell commands (approval-gated, subject to command rules).shell— run a command in a persistent shell that rememberscdand exported environment state between calls (approval-gated; see below).shell_jobs— start, list, read, or kill detached background commands (approval-gated; see below).update_todos— keep the visible task list in sync with multi-step work.task— delegate a focused investigation to a subagent with its own context (approval-gated; see below).ask_user— ask a clarifying question with optional choices (interactive sessions only).web_fetch,web_search— read a page or search the web; read-only, and local/private addresses are blocked by default (see below).browser— drive an optional headless Chromium page (screenshot, click, type, evaluate) when Playwright is installed and browser automation is enabled (approval-gated; see below).remember,recall— persist and read durable facts across sessions (see below).git,git_write— inspect status/diff/log and stage, unstage, commit, or create a branch (see below).forge,forge_write— list/view or create pull requests/merge requests and issues through thegh/glabCLI (see below).read_clipboard,write_clipboard— read the system clipboard or copy text to it (see below).http_get,http_request— exercise an HTTP API and inspect the response (see below).lsp_diagnostics,lsp_definition,lsp_references— language-server diagnostics and navigation, when enabled (see below).
Persistent shell
run_bash starts a fresh process per call, so cd and exported environment
variables never survive between commands. The shell tool instead drives one
long-lived shell per session (/bin/sh on POSIX, Git Bash on Windows; install
Git for Windows, or turn it off with config shell persistent off) so state
sticks:
shell: cd backend
shell: source .venv/bin/activate
shell: pytest -q # runs inside backend with the venv active
- The shell starts in the session workspace root. Output (stdout + stderr combined) is capped at 30 KB with a truncation note, and every call reports the exit code.
- A command that exceeds the timeout (default 120 s) is killed and the shell is restarted, so a hung command can never wedge the session.
shell_jobsruns commands detached from the shell and captures their output under~/.kiwimatecoder/jobs/shell/.action: listshows tracked jobs,action: outputreads one, andaction: killterminates it. At mostshell.max_jobs(default 8) run at once.- Settings:
/config shell [show|persistent on|off|timeout <s>|max-jobs <n>]in the REPL, orkiwimatecoder config shell ...from the shell. - Exiting the session terminates the persistent shell and every tracked
background job.
run_bashis unchanged and still the right tool for one-shot commands.
Command sandboxing
On macOS and Linux you can execute run_bash (and the persistent shell and its
background jobs) through an OS-level sandbox. It is off by default:
kiwimatecoder config sandbox show
kiwimatecoder config sandbox enable on
kiwimatecoder config sandbox network off # block network access
kiwimatecoder config sandbox add-path ~/shared # extra writable directory
The REPL equivalent is /config sandbox [show|enable on|off|network on|off| add-path <path>|remove-path <path>|clear-paths].
- macOS uses seatbelt via
sandbox-exec:process*is allowed, reads are broadly allowed, and writes are limited to the workspace,/tmp, andextra_writable. - Linux uses bubblewrap (
bwrap):/is mounted read-only, the workspace is read-write,/tmpis a private tmpfs, and--unshare-netis added when the network toggle is off. Install thebubblewrappackage to use it. - Windows has no supported backend; enabling it there falls back to running unsandboxed with a warning in the tool output.
- When the sandbox is enabled, the approval preview shows the wrapped command and the network mode. If the backend is missing or fails to start, the tool warns and runs the command unsandboxed rather than failing.
- Config lives in the
sandboxsection:{"enabled": false, "network": true, "extra_writable": []}.
Limitations: the sandbox is a damage-limiter for ordinary commands, not a security boundary against a hostile model or malicious code. Reads stay broad, the sandbox runs with your user's privileges (no user namespaces or credential isolation on macOS), and an unavailable backend silently degrades to an unsandboxed shell with only a warning. Read access to API keys stored on disk is not blocked, so use
--mode planor command rules when that matters.
Remote and devcontainer execution
Shell commands can run on another machine over SSH or inside a
devcontainer/Docker container. run_bash, the persistent shell, and
shell_jobs all execute remotely when it is configured; the approval preview
shows the wrapper and tool output includes a [remote] note. It is off by
default:
kiwimatecoder config remote show
kiwimatecoder config remote host devbox # ssh [user@]host
kiwimatecoder config remote user kiwi # optional
kiwimatecoder config remote port 2222 # optional (default 22)
kiwimatecoder config remote identity ~/.ssh/id_ed25519 # optional
kiwimatecoder config remote workspace /srv/app # cd before running
kiwimatecoder config remote devcontainer auto # auto|off|container name
kiwimatecoder config remote enable on
The REPL equivalent is /config remote [show|enable on|off|host <h>|user <u>| port <n>|identity <path>|workspace <path>|devcontainer <auto|off|name>].
When devcontainer is auto (the default), the first usable route wins:
- a
.devcontainer/devcontainer.jsonin the workspace and thedevcontainerCLI:devcontainer exec --workspace-folder <ws> sh -lc ...; - that detected container through
docker exec -w <workspaceFolder> <name> ...; - SSH when
remote.hostis set:ssh -o BatchMode=yes [-p <port>] [-i <identity>] [user@]host -- sh -lc ..., withcd <remote.workspace> && <command>when a remote workspace is set; - local execution with a warning in the tool output.
Set devcontainer off to skip detection, or name a container explicitly to
force docker exec. Remote wrapping happens first and a remote command is not
additionally wrapped in a local sandbox. If ssh, docker, or devcontainer
is missing, the command runs locally and the output carries the warning.
- Config lives in the
remotesection:{"enabled": false, "host": "", "user": "", "port": 22, "identity": "", "workspace": "", "devcontainer": "auto"}.identitymust point at an existing key file, and enabling remote execution requires a host (or an explicit container name). - The persistent shell starts through the same wrapper, so
cdand exported variables persist on the remote side. SSH uses agent/key auth only (BatchMode=yes); there is no password prompt.
Limitations: only commands run remotely. File tools (
read_file,write_file,edit_file,search, ...) still read the locally accessible workspace, so point them at the remote tree with sshfs, a bind mount, or a synced checkout. A full SFTP-backed file layer is deliberately not shipped: a half-working remote filesystem would silently split reads and writes between two machines. Detached agent jobs (/jobs) also run locally against that same local view. SSH host keys and identity files are the user's responsibility; remote command approval and command rules work exactly as they do locally.
Web access
web_search searches the web with the DuckDuckGo HTML endpoint (no API key)
and returns titles, URLs, and snippets. web_fetch downloads a page,
follows redirects, converts HTML to readable text, and summarizes binary
responses instead of dumping them. Both are read-only tools, so they run
without approval and stay available in plan mode, and both descriptions tell
the model to cite the URLs it relies on.
- Response size is capped with a truncation note; defaults are 50,000 characters and a 20-second timeout.
localhost, loopback/private/link-local IPs, and*.localhosts are refused by default. Enable them with/config web allow-local on(orkiwimatecoder config web allow-local on) when you are working against a local dev server.- Settings live under
/config web show|max-chars <n>|timeout <s>|allow-local <on|off>in the REPL, orkiwimatecoder config web ...from the shell. - DuckDuckGo parses the public HTML page, so result extraction is best-effort
and may need updating if that page's markup changes;
web_fetchis unaffected.
Proxy, custom CA, and offline mode
Every outbound request — chat streaming, model catalogs, web_fetch/
web_search, and embeddings — honors the network settings in
~/.kiwimatecoder/config.json:
{
"network": {
"proxy": "http://proxy.corp:8080",
"ca_bundle": "/etc/ssl/certs/corp-ca.pem",
"offline": false
}
}
Set them from the REPL with /config network ... or from the shell with
kiwimatecoder config network ...:
kiwimatecoder config network show
kiwimatecoder config network proxy http://proxy.corp:8080 # or: clear
kiwimatecoder config network ca /etc/ssl/certs/corp-ca.pem # or: clear
kiwimatecoder config network offline on # or: off
proxyroutes all requests through an HTTP(S) proxy (proxy/verifyare passed to the underlyinghttpxclients).ca_bundlepoints at a PEM file used instead of the system trust store for TLS verification — for corporate MITM proxies or self-signed CAs. The file must exist when set.offline onis air-gapped mode: cloud chat, model catalogs, web tools, and embeddings are refused with an "offline mode is enabled" error before any request is made. Local providers keep working —ollama,lmstudio,unsloth, and custom providers onlocalhost/*.localare still reachable for chat, catalog, and embedding calls.web_fetch/web_searchalways refuse offline because they only reach the public internet.
Browser automation
The browser tool drives a headless Chromium page through Playwright when you
opt in. Playwright is not installed by default, and the tool stays hidden until
browser automation is enabled:
pip install 'kiwimatecoder[browser]'
playwright install chromium
kiwimatecoder config browser enable on
Without the extra, the tool returns a clear install hint instead of failing; the base install keeps the same dependency set.
- The tool is approval-gated because a page can submit forms or trigger
downloads. In
askmode the preview showsbrowser <action> <url|selector>(scripts are redacted and capped). It is not advertised while disabled, and plan mode only advertises read-only tools. openaccepts onlyhttp(s)URLs and refuseslocalhost, loopback/private IPs, and*.localhosts unless/config web allow-local onis set. It reports the final URL after redirects and the page title.textreturns visible page text capped at ~30,000 characters with a truncation note.click/typetake a CSS selector, andevaluateruns JavaScript and returns a capped JSON-ish result.screenshotsaves a PNG to<workspace>/.kiwimatecoder/screenshots/<timestamp>.pngand attaches it to the next request, so a vision-capable model sees it exactly like aview_imageattachment. Thevisionper-turn count and size limits apply.- One page is shared by successive tool calls in a session;
close(and leaving the REPL) shuts Chromium down.timeout_mscan override the configured action timeout per call. - Settings live under
/config browser [show|enable on|off|headless on|off|timeout <ms>]in the REPL, orkiwimatecoder config browser ...from the shell (defaults: off, headless on, 15,000 ms; timeout range 1s–120s). Changing a setting closes the live page so the next call starts with the new values.
Open https://example.com/docs and summarize the visible text.
Screenshot the pricing page and tell me what stands out.
Fill the search box with "playwright" and click Search.
Git and forge tools
The agent can inspect and change git state through dedicated tools instead of
dropping to run_bash:
git(read-only) —status,diff(staged or not, optionally against a ref),log(1–100 commits),show <ref>, andbranches.git_write(approval-gated) —stage,unstage,commit(a non-empty message is required), andcheckout_branch(creates a new branch). The approval prompt shows the exactgit ...command line.forge(read-only) —pr_list,pr_view,issue_list, andissue_viewfor the forge detected from theoriginremote.forge_write(approval-gated) —pr_createandissue_create.
Forge integration goes through the official CLI (gh for GitHub, glab for
GitLab), so your existing CLI login is used and no token is read or stored by
KiwiMateCoder. The matching CLI must be installed and authenticated; on
GitLab, pull requests are handled as merge requests (glab mr ...).
Intentionally out of scope: push, reset, clean, and any forge
merge/close/delete command. Those stay manual, or go through run_bash where
the command rules and approval prompt apply.
Clipboard and HTTP tools
Clipboard access uses the platform's standard tool, discovered on PATH and
run without a shell: pbpaste/pbcopy on macOS, wl-paste/wl-copy
(preferred) or xclip on Linux, and PowerShell's Get-Clipboard/
Set-Clipboard on Windows. If none is installed the tool returns a clear
install hint instead of failing.
read_clipboardis read-only, so it runs without approval.write_clipboardis approval-gated and the preview shows the redacted text (clipped to ~200 characters).
http_get and http_request exercise HTTP APIs and print the status line,
selected response headers, and the body (JSON is pretty-printed, bodies are
truncated with a note). 4xx/5xx responses are returned for inspection rather
than raised, and httpx errors are converted to friendly messages.
http_get(url, headers?)is read-only.http_request(method, url, headers?, body?, json?, timeout?)is approval-gated because it can change remote state. Methods are GET, POST, PUT, PATCH, and DELETE;body(raw text) andjsonare mutually exclusive.- Both reuse the
websettings: response size and timeout come from/config web max-chars//config web timeout, and local/private addresses stay blocked unless/config web allow-local on.
Read what's on my clipboard and save it to notes.txt.
Copy the test command to my clipboard.
GET https://api.github.com/repos/psf/requests and summarize the JSON.
POST https://httpbin.org/post with json {"hello": "world"}.
Images
Attach images to a message three ways, all sharing the same size and count limits:
- Type
@path/to/image.pngin a prompt. Existing image files under the workspace are attached and removed from the text (a lone@image.pngsends "Please analyze the attached image(s)."). Paths that are missing, outside the workspace, or not images are left in the text untouched. - Paste or drag an image into the terminal. Most terminals insert the file path
at the cursor;
@-mention extraction then attaches it on send. - Let the model call the
view_imagetool when it needs to look at a file.
Each image is validated (extension and magic bytes), base64-encoded, and sent
to the model as an image part on the next request. Both OpenAI-compatible and
native Anthropic providers are supported. Limits live under
/config vision [show|max-bytes <n>|max-images <n>] (defaults: 5 MB per image,
4 images per turn); oversized or invalid images produce a clear message instead
of a failed request.
Image and video generation
Generate images and short videos with your provider's media API and keep them in the workspace. Generation is opt-in and approval-gated because it costs money:
/config media enable on
/config media provider openai
/image model list # pick an image model (or: /image model <id>)
/config media size 1024x1024
/image a red fox reading a book
Media models are chosen per provider, and there is no default: ids and prices
change quickly, so you pick one yourself. /image model shows the current image
model for the media provider; /image model list lists that provider's image
models (a picker in an interactive session, a table otherwise), /image model refresh re-fetches the list, /image model search <term> filters it, and
/image model <id> sets an id directly (a single word: anything else is treated
as a mistyped prompt). /video model takes the same arguments for video.
/media provider shows the providers with their models (a picker when
interactive); /media provider <id> switches the provider the media tools use
and, interactively, offers to choose any missing models. Each provider remembers
its own image and video model, so switching providers does not lose your choice.
Because model is a subcommand, a prompt that starts with the word
model needs -- first (/image -- model railway in the snow).
/image [--size WxH] [--model <id>] <prompt> saves a PNG under
.kiwimatecoder/media/ and queues it for the next request. Options come before
the prompt, which is taken verbatim (quotes included); use -- if a prompt
starts with dashes. The same generation is available to the model as the
generate_image tool: it asks for approval first, with a preview showing the
provider, model, size, and prompt. Responses are accepted as
data[0].b64_json or data[0].url (URL downloads are capped at 20 MB and
honor offline mode and the local-address guard). OpenAI-compatible providers
are called at /images/generations; OpenRouter at /images.
Video uses the same switch and provider but its own model, which you choose yourself (there is no default: ids and prices change quickly and a clip is billed per second):
/media provider openrouter
/video model list # pick a video model (or: /video model <id>)
/config media duration 5 # seconds
/config media video-size 720p # or 1280x720; "default" clears it
/video a paper boat drifting down a rainy street
/video --duration 8 --size 1080p --image start.png the boat starts to sail
/video [--duration <s>] [--size <WxH|720p>] [--model <id>] [--image <path>] <prompt> submits an asynchronous job, shows live status while it renders
(usually a few minutes), and streams the finished file to
.kiwimatecoder/media/ with a 500 MB cap. --image animates a workspace image
as the first frame (OpenRouter models). Press Ctrl+C to stop waiting: the job
keeps running (and billing) on the provider, and /video resume <job-id> fetches
it later without paying twice. Polling is bounded to 15 minutes and tolerates
brief network errors; the API key is only ever sent to the provider's own host,
never to a download CDN. The model can call the approval-gated generate_video
tool (its preview states the per-second billing); after a timeout it resumes with
resume_job_id rather than regenerating.
Two wire formats are spoken, chosen from the provider's host: OpenRouter
(duration, resolution/size, frame_images, unsigned_urls) and the OpenAI
Videos API (seconds, size, multipart form, /videos/<id>/content). The OpenAI
format is covered by mocked-transport tests only; please report anything a live
endpoint rejects.
/media shows whether image and video generation are ready (and what is missing:
disabled, offline, no API key, no model chosen) and lists the most recent files;
reference an image from the list with @<path> to attach it again. Provider auth,
API versioning (Azure-style ?api-version=), proxy, and custom CA settings all
come from the normal config. Configure it from the shell with
config media show|enable on|off|model <id|none> [--provider <id>]|provider <id>|size <WxH>|video-model <id|none> [--provider <id>]|duration <seconds>|video-size <size>|output-dir <path>
(inside the REPL, /config media model <id|none> [provider] and /config media video-model <id|none> [provider] take the provider as an optional trailing word;
none, clear, default or - clears the model for that provider).
Notebooks, PDFs, and docx
read_file extracts structured documents to text automatically, so the model
can read them without extra tooling:
- Jupyter notebooks (
.ipynb) render as## Cell N (type)sections with cell sources plus text and stream outputs; image outputs are summarized as[image/png output, N bytes]. - Word documents (
.docx) are unzipped andword/document.xmlis stripped to text with paragraph and line breaks preserved. - PDFs (
.pdf) use thepdftotextCLI (from Poppler) when installed for reliable extraction. When it is missing, a conservative stdlib fallback inflates FlateDecode streams and reads text fromBT/ETblocks; if nothing is parseable the result explains how to installpdftotextinstead of failing.
Document output is capped at ~200 KB with a truncation note, and offset/
limit are ignored for documents (they apply to plain text files only).
Malformed documents always return a clear message rather than raising.
Providers
KiwiMateCoder ships a built-in registry of providers. Switch live with /provider,
or set the persistent primary from the shell with config provider use <id>. An
API key can be saved interactively with kiwimatecoder setup, directly with
config key set <provider> <key>, or via the provider's environment variable.
You can also add OpenAI-compatible custom providers with config provider add.
| Provider id | Key env var | Notes |
|---|---|---|
kiwimate (experimental) |
KIWIMATE_API_KEY |
kiwimate.net; keys start with sk-km-. Chat only — no tool use yet (see below). |
openai |
OPENAI_API_KEY |
|
anthropic |
ANTHROPIC_API_KEY |
Native Messages API. |
google |
GEMINI_API_KEY |
|
xai |
XAI_API_KEY |
|
mistral |
MISTRAL_API_KEY |
|
deepseek |
DEEPSEEK_API_KEY |
|
qwen |
DASHSCOPE_API_KEY |
|
moonshot |
MOONSHOT_API_KEY |
|
openrouter |
OPENROUTER_API_KEY |
The provider used until you pick another. |
azure |
AZURE_OPENAI_API_KEY |
Placeholder endpoint; the model is your deployment name. |
bedrock |
AWS_BEARER_TOKEN_BEDROCK |
Placeholder endpoint. |
groq |
GROQ_API_KEY |
|
together |
TOGETHER_API_KEY |
|
fireworks |
FIREWORKS_API_KEY |
|
cerebras |
CEREBRAS_API_KEY |
|
deepinfra |
DEEPINFRA_API_KEY |
|
ollama |
OLLAMA_API_KEY (optional) |
Local. |
lmstudio |
LMSTUDIO_API_KEY (optional) |
Local. |
unsloth |
UNSLOTH_API_KEY (required) |
Local. |
Choosing a model
There are no default models. You choose the model to use with each provider when you add it, and the choice is remembered per provider:
kiwimatecoder setupasks you to pick one from the provider's list after it saves the key (or pass--model <id>to skip the picker)./providerasks for a model for each provider you add to the roster.- Custom providers take the model as the fourth argument of
config provider add <id> <name> <base_url> <model>; change it withconfig provider edit <id> --model <id>or/config provider edit <id> model=<id>. config model set <id> [--provider <id>]or/config model set <model> [provider]changes the model for the active (or named) provider, andconfig model reset [--provider <id>]//config model reset [provider]forgets it.config provider listshows each provider's chosen model.
The interactive REPL asks for a model at launch when the primary has none. A
fallback provider without a chosen model is skipped (with a note) during
failover. Headless runs never prompt: kiwimatecoder -p, ask, and jobs run
exit 1 with No model chosen for <provider>… when neither --model nor a
chosen model is available (eval run reports the same message as invalid
input, exit 2). Local servers are the one exception — with nothing chosen,
the session uses the first model the running server lists.
Groq, Together, Fireworks, Cerebras, and DeepInfra work out of the box once their API key is set — they speak the standard OpenAI-compatible protocol.
KiwiMate (experimental)
kiwimate is KiwiMate's own OpenAI-compatible API from
kiwimate.net. It is listed first in every provider
picker, in its own Experimental box, and marked (experimental) in
config provider list. Create a key at kiwimate.net/developers/console (it
starts with sk-km-), then run kiwimatecoder setup --provider kiwimate (or
set KIWIMATE_API_KEY, then config provider use kiwimate and config model set <id>). Setup offers the endpoint's models, falling back to the suggested
kiwimate-mini-1-0, kiwimate-small-1-0, kiwimate-medium-1-0, and
kiwimate-large-1-0, and reminds you that the provider is experimental.
The endpoint is limited for now:
- Chat only, no tool use yet. KiwiMateCoder sends it no tool schemas, so with KiwiMate as the provider the agent cannot read or edit files or run commands. Tool calls and results already in the conversation are flattened into plain text when you switch to it mid-session.
- Replies are capped at about 1,024 tokens. The REPL prints
The reply was cut off at the provider's output limit.when that happens. - System prompts are ignored by the endpoint, so project instructions
(
AGENTS.md), memory, output styles, and custom prompts do not reach the model. Only the last 20 non-system messages of the conversation are forwarded to it.
azure and bedrock ship placeholder endpoints because the endpoint is
account-specific (https://<resource>.openai.azure.com/openai/v1 and
https://bedrock-runtime.<region>.amazonaws.com/openai/v1). Point them at your
own resource by adding a custom provider (built-in entries cannot be edited):
kiwimatecoder config provider add my-azure "My Azure" \
https://my-resource.openai.azure.com/openai/v1 my-deployment \
--key-env AZURE_OPENAI_API_KEY --key-header api-key --key-prefix "" \
--api-version 2024-10-21
kiwimatecoder config key set my-azure <key>
kiwimatecoder config provider add bedrock-eu "Bedrock (eu-central-1)" \
https://bedrock-runtime.eu-central-1.amazonaws.com/openai/v1 \
openai.gpt-5.6-sol --key-env AWS_BEARER_TOKEN_BEDROCK
Azure OpenAI authenticates with an api-key header (no Bearer prefix) and
versions its API with ?api-version=; both are configurable per custom provider
(--key-header, --key-prefix, --api-version, or the slash equivalents).
AWS Bedrock's OpenAI-compatible endpoint accepts a bearer token only: SigV4/IAM
signing, Azure managed identity, Google Vertex AI (project-specific endpoint,
OAuth2-only auth), and interactive OAuth/device-code flows are not implemented
(deferred; see ROADMAP).
Each built-in provider still ships a short list of suggested model ids, used
only to fill the pickers when its live listing is unavailable — none of them is
used unless you choose it. The live catalog below is what /model actually
offers once the provider can be queried (see Needs a key below).
The anthropic provider talks to Anthropic's native Messages API, including
streaming tool calls and native model listing. Custom providers can opt into the
same path with config provider edit <id> --compat anthropic (or
/config provider edit <id> compat=anthropic); everything else speaks the
OpenAI-compatible chat+tools protocol.
Local providers (Ollama, LM Studio & Unsloth)
The ollama, lmstudio, and unsloth providers talk to model servers on your
own machine. Make sure the server is running (Ollama on
http://localhost:11434, LM Studio's local server on
http://localhost:1234, or Unsloth's Studio API on
http://localhost:8888), then:
/provider ollama
That's it for Ollama and LM Studio — no API key needed. You can choose a model
like any other provider (kiwimatecoder setup offers the server's models when
it is running, and /model lists them); until you do, the session uses the
first model the server lists. kiwimatecoder setup detects which local servers
are running and marks them in the picker. Tool calling depends on the model you
pick, so choose a tool-capable family (Llama 3.1+, Qwen 3, DeepSeek, ...).
unsloth works the same way but requires a key: Unsloth enforces auth even
on localhost. Create one in Unsloth under Settings → API (it starts with
sk-unsloth-), run kiwimatecoder setup --provider unsloth to save it, and
load a GGUF model in Unsloth before chatting. Tip: start Unsloth's server with
--disable-tools when an external agent drives it — otherwise Unsloth's own
server-side tools swallow the agent's tool calls.
A key only matters if your server enforces auth (e.g. LM Studio's server token,
or Ollama behind an authenticating proxy) — set OLLAMA_API_KEY /
LMSTUDIO_API_KEY or config key set ollama <key> in that case. Running on a
different port or another machine? Add it as a custom provider instead, with
the model to use as the fourth argument:
/config provider add mybox "My Box" http://mybox.local:11434/v1 llama3.1:8b —
any localhost/*.local provider is treated as keyless automatically.
Model catalogs
Model ids drift constantly, so the list /model offers is fetched from the
provider itself rather than being frozen into the release.
- Newest first. Opening
/model(or running/model refresh) calls the provider's/modelsendpoint and offers what it serves today, ordered by release date, with your current model pinned first. Search (/model search <term>) bypasses this newest-first cap and scans the whole catalog by name. - Deprecated ids disappear. Anything the provider no longer lists is dropped
from the catalog, and
/model refreshprints what was removed. If your current model is one of them, it says so. - Only usable models. Embedding, image, audio, moderation, and non tool-calling models are filtered out — the agent loop needs text chat plus tool calls (chat-only providers such as KiwiMate keep models without tool support). The newest 60 are offered; any other id still works if you type it.
- Cached for a day. Results are stored in
~/.kiwimatecoder/model_cache.jsonand reused for 24 hours, so the selector stays instant and tab completion never touches the network. A failed fetch falls back to the cached list, then to the built-in suggestions, and is not retried automatically for 30 minutes. - Needs a key. A cloud provider is only queried once it has an API key
configured; keyless local servers (
ollama,lmstudio, and any custom provider onlocalhostor a*.localhost) are queried without one —unsloth, which enforces auth locally, is queried once its key is set.
From the shell, kiwimatecoder config models show [--provider <id>] and
kiwimatecoder config models refresh [--provider <id>] show or refresh the same
catalog.
The suggested model tuples in kiwimatecoder/providers.py are only the offline
fallback for the pickers (never a default), and custom providers can list
theirs via a "models" array in ~/.kiwimatecoder/config.json. /config models allow|deny reshapes what is offered on top of whichever catalog is in use, and
/model <name> or config model set <name> accepts any id, listed or not.
One-shot mode
For a quick question without entering the REPL:
kiwimatecoder ask "how do I reverse a list in python?"
kiwimatecoder ask "review this file" --file app.py --provider openai --model gpt-5.6-sol
ask uses the model chosen for the provider unless --model is passed, and
exits 1 with No model chosen for <provider>… when there is neither.
Headless mode
Run one agentic turn without entering the REPL — useful for scripts and CI:
kiwimatecoder -p "Summarize the changes in the working tree."
echo "Explain src/app.py" | kiwimatecoder -p -
kiwimatecoder -p "Summarize the changes." --provider openai --model gpt-5.6-sol
The prompt is the value of -p/--print; -p - reads it from stdin. The run
uses the model chosen for the provider (kiwimatecoder setup or config model set); pass --model to override it, or when none is chosen — headless runs
never prompt for one. Flags:
| Flag | Meaning |
|---|---|
--output-format text|json|stream-json |
text streams assistant text to stdout (default); json prints one JSON object at the end; stream-json prints one compact JSON object per event, ending with a result line. |
--mode ask|auto-accept|plan |
Permission mode for this run (default: the configured mode). |
--yes |
Treat approvals as granted (auto-accept) — never prompts. |
--max-turns N |
Hard cap on tool-loop iterations (default 30). |
--provider, --model |
Provider/model overrides for this run. --provider makes that provider the primary, ahead of the configured roster; --model is required when no model is chosen for it. |
--workspace PATH |
Workspace root (default: current directory). |
--quiet |
Suppress tool/progress lines on stderr in text mode. |
Tool and progress lines go to stderr; only assistant text (text mode) or
JSON (json/stream-json modes) goes to stdout. Headless runs never prompt:
actions that would need approval are denied with a note on stderr unless
--yes or --mode auto-accept is used.
Exit codes: 0 success, 1 runtime failure (missing key or model — No model chosen for <provider>… on stderr — provider error, turn cap without a final
answer), 2 invalid usage (bad format, mode, provider, or workspace).
CI example (a fresh runner has no saved config, so pass --model):
- name: Review the diff
run: |
kiwimatecoder -p "Review the staged diff and list risks." \
--model anthropic/claude-sonnet-5 \
--output-format json --max-turns 10 > review.json
cat review.json
More recipes (ready-made GitHub Actions workflows, exit-code gating, and pre-commit setup) live in docs/ci.md.
Shell completions and man page
Typer ships shell completion for bash, zsh, fish, and PowerShell:
kiwimatecoder --install-completion # detect and install for your shell
kiwimatecoder --show-completion bash # print the script to stdout instead
A troff man page is committed at docs/kiwimatecoder.1; view it with man ./docs/kiwimatecoder.1 (on Linux, man -l docs/kiwimatecoder.1). Regenerate it
from the Typer command tree after changing the CLI:
python scripts/generate_man.py # rewrite the man page
python scripts/generate_man.py --check # fail when the committed file is stale
Interactive sessions need a real terminal. When stdin is not a TTY (a pipe, a
CI job, cron), the bare command — and --resume/--continue — exits with code
2 and a note pointing at headless mode instead of starting prompt_toolkit.
Use kiwimatecoder -p "..." or echo "..." | kiwimatecoder -p -.
Python SDK
Embed the agent in a Python program with kiwimatecoder.sdk:
from kiwimatecoder.sdk import run_agent_sync
result = run_agent_sync(
"Summarize README.md in three bullets.",
workspace=".",
mode="plan",
model="anthropic/claude-sonnet-5", # omit to use the provider's chosen model
)
if result.success:
print(result.text)
print(result.usage, result.cost_usd) # tokens and estimated USD (or None)
Without model=, the run uses the model chosen for the provider. When there
is none, run_agent/run_agent_sync raise
kiwimatecoder.config.ModelNotChosenError (a ValueError) before contacting
the provider.
RunResult carries text, usage (prompt_tokens/completion_tokens),
cost_usd, provider, model, mode, tools_used, messages, success,
and error. Pass on_event to observe the same events as stream-JSON
(text_delta, tool_start, tool_end, usage, done), confirm to
approve actions, and console to receive the agent's tool/progress output.
Approvals are denied by default. From async code use await run_agent(...);
run_agent_sync raises a clear error if called inside a running loop.
Editor integration (ACP)
KiwiMateCoder can run as an Agent Client Protocol (ACP) agent over stdio, so an ACP-capable editor can drive it:
kiwimatecoder acp [--workspace PATH]
A Zed-style agent configuration (settings.json) looks like:
{
"agent": {
"command": "kiwimatecoder",
"args": ["acp"]
}
}
The server speaks JSON-RPC 2.0 over newline-delimited JSON on stdin/stdout; the only thing ever written to stdout is protocol traffic. Implemented subset:
initializehandshake with agent capabilities and version info.session/newcreates one conversation rooted at the client'scwd, using the configured permission mode (never an assumed auto-accept).session/promptruns one agent turn, streaming assistant text chunks and tool-call progress assession/updatenotifications; the response carriesend_turn,cancelled,refusal, ormax_tokens.session/cancelcancels the running turn; partial assistant text is kept.session/request_permissionbridges every write/command approval to the editor when the session runs inaskmode. Approving with "always" persists the tool allowlist; a cancelled or unanswered request (default timeout 300s,config acp timeout <s>) is denied exactly like a normal denial.
This is a focused subset: terminal and MCP client capabilities advertised by
the editor are not wired through (MCP servers still come from KiwiMateCoder
config), loadSession is not supported, image prompt parts are ignored with a
note to the model, and the file tools operate on the local filesystem. When
the client advertises fs.readTextFile/fs.writeTextFile, the server exposes
read_text_file/write_text_file helpers that delegate to
fs/read_text_file/fs/write_text_file; otherwise those helpers use the
local filesystem.
Background jobs
Run an agent task detached from your terminal, then check on it later:
kiwimatecoder jobs run "Add type hints to kiwimatecoder/jobs.py and run mypy."
kiwimatecoder jobs run "Fix the failing test." --provider openai --model gpt-5.6-sol
kiwimatecoder jobs list
kiwimatecoder jobs show <id>
kiwimatecoder jobs output <id>
kiwimatecoder jobs cancel <id>
kiwimatecoder jobs clear # finished jobs only; --all includes running
Each job is one headless run (python -m kiwimatecoder -p ... --output-format json) recorded as JSON under ~/.kiwimatecoder/jobs/<id>.json with its combined
output at ~/.kiwimatecoder/jobs/<id>.log. Records survive restarts; jobs list
refreshes running jobs from their process and parsed result, and corruption in
one record never hides the others. A job uses the model chosen for its provider
unless --model is passed; jobs run and jobs schedule check this before
starting anything and exit 1 with No model chosen for <provider>… when
there is neither.
Warning:
jobs rundefaults to--mode auto-accept, so an unattended job can edit files and run commands without asking. Pass--mode ask(approvals are then denied, since nothing can prompt) or--mode plan(read-only) to constrain a job, and only point jobs at workspaces you trust.
Inside a session, /jobs [list|show <id>|cancel <id>|tick] does the same, and
/jobs run <prompt> starts a job in the session's workspace (still
auto-accept). Jobs are marked running, succeeded, failed, or
cancelled; cancelled covers an explicit jobs cancel.
Scheduling
Scheduling is pull-based — there is no daemon and no platform cron integration.
jobs schedule "<prompt>" --every <seconds> starts a run immediately and stores
the interval plus a next_run_at timestamp; every later invocation of
kiwimatecoder jobs tick (or /jobs tick) starts any run that is due. A job
that is still running is skipped, so runs never overlap. A due job that cannot
start (its workspace is gone, its provider was removed, or no model is chosen)
is left in place and reported as Skipped <id>: <reason>; jobs tick then
exits 1. Wire jobs tick to your own scheduler, for example:
*/5 * * * * kiwimatecoder jobs tick
Update
Update the CLI from the same Python environment:
kiwimatecoder update
or with a flag:
kiwimatecoder --update
(The older -update form still works but is deprecated.) Check the installed
version before/after with:
kiwimatecoder --version
When KiwiMateCoder is running from a Git checkout, the updater first fetches
origin and compares the local HEAD to origin/<branch>:
- Already up to date — prints
Already on the latest version (commit <sha>).and exits without pulling or reinstalling. - Behind — prints
Updating from <old-sha> (N commit(s) behind origin/<branch>)…, runsgit pull --ff-only, reinstalls the checkout withpip install --upgrade -e <path>, and reportsUpdated <old-sha> → <new-sha>.
KiwiMateCoder is not published to PyPI, so for packaged (non-Git) installs the
fallback runs
pip install --upgrade --force-reinstall git+https://github.com/Kyle8933/kiwimatecoder.git.
Updating and pinning versions
Pin a branch, tag, or commit with --ref:
kiwimatecoder update --ref v0.1.0 # tag
kiwimatecoder update --ref main # branch
kiwimatecoder update --ref 1a2b3c4 # commit
In a Git checkout the updater fetches origin and then puts the checkout on
the ref: the current branch is fast-forwarded with git pull --ff-only (local
commits are never merged unexpectedly), while every other ref is a plain
git checkout followed by pip install --upgrade -e <path>. The command
prints the old and new commit SHAs. For packaged installs it reinstalls
git+https://github.com/Kyle8933/kiwimatecoder.git@<ref>.
To roll back, pin an older tag or commit the same way; kiwimatecoder --version
shows the installed version. Generate a software bill of materials for the
installed environment with:
python scripts/generate_sbom.py --output sbom.json
It is stdlib-only, emits CycloneDX-shaped JSON with the package and direct
dependency versions, and is uploaded as a CI artifact by the sbom job.
Project instructions
Drop an AGENTS.md (or CLAUDE.md, .kiwimatecoder/AGENTS.md,
.kiwimatecoder/instructions.md) at the workspace root and its contents are
loaded into the system prompt on every turn — build commands, style rules,
testing conventions. Files are capped at 32KB each and 48KB total.
Memory
The agent can remember durable facts about you and your projects across
sessions. Memory is plain Markdown, one - fact bullet per line, in two
scopes:
- Project —
<workspace>/.kiwimatecoder/memory.md; travels with the repository and applies only there. - User —
~/.kiwimatecoder/memory.md; shared across every workspace.
The model writes with the approval-gated remember tool (scope=project or
scope=user) and reads with the read-only recall tool. Active facts are
loaded into the system prompt on every turn, capped at 16KB by default so a
pathological file cannot crowd out the conversation.
Manage memory directly with /memory:
/memory # show both files and their facts
/memory add The build uses uv, not pip
/memory add-user I prefer concise answers
/memory clear project
/memory clear user
Settings live under kiwimatecoder config memory show|max-bytes <n>|enable on|off.
Never store secrets or API keys in memory — the prompt section says so
explicitly, and the remember preview runs the same secret redaction as audit
output.
Custom commands and prompt templates
Drop a Markdown file in <workspace>/.kiwimatecoder/commands/ (or
~/.kiwimatecoder/commands/) and its filename becomes a slash command. The
body is the prompt sent as a normal user turn; $ARGUMENTS is replaced with
whatever you type after the command, and the arguments are appended when the
token is absent. Workspace templates win over user templates with the same
name, and built-in commands always win over templates. /templates lists what
was discovered; /help adds a Custom commands group.
# .kiwimatecoder/commands/review.md
# Review the current diff
Review $ARGUMENTS for bugs, security issues, and missing tests.
/review src/app.py
Agent Skills
Skills are Markdown instruction bundles the model loads only when a task
matches, so they cost no tokens on turns that do not use them. Each skill is a
directory containing SKILL.md:
<workspace>/.kiwimatecoder/skills/pdf/SKILL.md # project skill
~/.kiwimatecoder/skills/pdf/SKILL.md # personal skill
The system prompt lists each skill's name and first line only; the model calls
the read-only load_skill tool to pull the full body (capped at 32KB).
Workspace skills shadow user skills with the same name.
Plugins
Plugins are Python files with a register(api) entry point that can add tools,
slash commands, and event subscribers without forking the CLI:
from kiwimatecoder.tools.base import FunctionTool, ToolResult
def register(api):
api.register_tool(FunctionTool(
name="word_count",
description="Count words in a file.",
parameters={
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
func=lambda args, session: ToolResult(content="..."),
))
api.register_command("hello", lambda arg, session, console: "continue")
api.subscribe("post_tool", lambda event: None)
User plugins load from ~/.kiwimatecoder/plugins/*.py. Project plugins in
<workspace>/.kiwimatecoder/plugins/*.py are disabled by default — cloning
a repository must never execute code just because the CLI started in it. Opt in
with "plugins": {"allow_project": true} in ~/.kiwimatecoder/config.json, and
skip individual plugins with "plugins": {"disabled": ["name"]}. A plugin that
fails to import or register is reported as a dim warning and skipped; it never
prevents startup.
MCP servers
MCP (Model Context Protocol) servers extend the agent with tools it discovers
at session start. Configure them under mcp_servers in
~/.kiwimatecoder/config.json — each entry is either a stdio subprocess or an
HTTP endpoint:
{
"mcp_servers": {
"files": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
"env": {"SOME_TOKEN": "..."},
"disabled": false
},
"remote": {
"url": "https://mcp.example.com/mcp",
"headers": {"Authorization": "Bearer sk-..."},
"disabled": false
}
}
}
From the shell, kiwimatecoder config mcp add <name> writes the same entries
(set exactly one of --command or --url):
kiwimatecoder config mcp add files --command npx --args "-y @modelcontextprotocol/server-filesystem /tmp"
kiwimatecoder config mcp add remote --url https://mcp.example.com/mcp -H "Authorization: Bearer sk-..."
kiwimatecoder config mcp list
kiwimatecoder config mcp remove remote
In the REPL, /mcp list shows every configured server, its status (connected,
disabled, or the failure reason), its resources count, and the registered tools.
/mcp reload reconnects each enabled server and re-registers its tools without
restarting the session.
Each server tool is registered as mcp__<server>__<tool> (both parts sanitized
to [A-Za-z0-9_]), with the server's JSON Schema used for arguments. Tools that
declare annotations.readOnlyHint run without approval; every other MCP tool
prompts for approval in ask mode, exactly like write_file or run_bash.
A server that fails to start or initialize is reported as a dim warning and
skipped — it never blocks startup. Connections close when the session exits.
Authentication is whatever headers (HTTP) or environment variables (stdio) you configure. Interactive OAuth is not implemented yet; see ROADMAP.md.
Language server diagnostics
When enabled, KiwiMateCoder can talk to language servers for compiler-grade diagnostics and navigation. It is opt-in and off by default; no server process starts until the feature is enabled and a matching file is queried.
lsp_diagnostics— errors and warnings for one file, or for the five most recently touched files when no path is given.lsp_definition/lsp_references— where a symbol is defined, and every place it is used. Positions are 1-based line and column numbers.
Built-in presets start automatically when their command is on PATH:
| Language | Command | Extensions |
|---|---|---|
| python | pyright-langserver --stdio |
.py, .pyi |
| typescript | typescript-language-server --stdio |
.ts, .tsx, .js, .jsx |
| go | gopls |
.go |
| rust | rust-analyzer |
.rs |
| c/cpp | clangd |
.c, .h, .cpp, .hpp |
After a successful write_file/edit_file, diagnostics for the edited file
are appended to the tool result as LSP: lines (capped at ten) when
diagnostics_after_edits is on. A timeout or missing server appends nothing,
so LSP can never fail a turn or delay it beyond the configured timeout.
Enable it in-session with /lsp on, or from the shell:
kiwimatecoder config lsp enable on # on | off
kiwimatecoder config lsp after-edits on # on | off
kiwimatecoder config lsp show
Use /lsp status to see whether LSP is on, which server commands are
installed, and which clients are running; /lsp restart stops running servers
so they start fresh on next use. Settings live under lsp in
~/.kiwimatecoder/config.json; add your own server or override a preset:
{
"lsp": {
"enabled": true,
"timeout": 10.0,
"diagnostics_after_edits": true,
"servers": {
"python": {
"command": "basedpyright-langserver",
"args": ["--stdio"],
"extensions": [".py", ".pyi"]
}
}
}
}
Codebase index and semantic search
search gains a third mode: mode='semantic' ranks files against a
natural-language query using a local, persistent index instead of a regex, and
returns paths, line numbers, and source snippets. The agent chooses it for
questions like "where is authentication handled?", and grep/glob keep working
exactly as before.
The index is built automatically the first time semantic search runs, then
refreshed incrementally: only files whose size or modification time changed
are re-tokenized, deleted files are dropped, and .gitignore plus the default
skip directories (node_modules, venv, __pycache__, …) are respected.
Binary files, files larger than the byte cap, and anything beyond the file cap
are skipped. It is a cache: the store lives at
~/.kiwimatecoder/index/<hash-of-workspace>.json and clear simply deletes it.
/index # status: files, terms, store size, stale count, embeddings
/index build # refresh incrementally; prints added/updated/removed
/index clear # delete the store for this workspace
Ranking uses BM25 over file term frequencies, so there are no API calls and
semantic search works out of the box. Settings live under the index key:
{
"index": {
"enabled": true,
"max_files": 5000,
"max_file_bytes": 262144,
"embeddings": { "provider": "", "model": "", "batch_size": 32 }
}
}
Embeddings are optional and OpenAI-compatible only: set a provider id and
an embedding model (the provider must serve POST /embeddings and its API key
is read from the same config/env as chat) to additionally store chunk vectors.
When vectors exist, search blends the lexical and vector scores; if the
embedding provider is unavailable or errors for any reason, search silently
falls back to lexical ranking. Embeddings are never required to use the
feature.
kiwimatecoder config index show
kiwimatecoder config index embed-provider openai
kiwimatecoder config index embed-model text-embedding-3-small
kiwimatecoder config index embed-provider none # turn embeddings off
kiwimatecoder config index clear
Subagents
The task tool delegates a focused, self-contained investigation to a
subagent that runs in its own context with the same workspace, provider, and
tools. The subagent's intermediate tool output stays out of the parent
conversation; it returns a final report (plus a step/token count) as the tool
result. Use it for broad searches or self-contained questions that would
otherwise flood the main context.
- Spawning a subagent is approval-gated like a command because the subagent can
write files and run commands. Its own actions still go through the normal
permission gate (including plan mode and command rules), and its edits are
checkpointed so
/undocovers them. - Subagents cannot spawn nested subagents and cannot use
ask_user; put every decision they need in the prompt. - A subagent shares the parent's remaining token budget and stops at the
configured step limit, returning a partial report with a note when either cap
is hit. While subagents are disabled,
taskis not advertised at all.
{
"subagents": {
"enabled": true,
"max_steps": 20,
"model": ""
}
}
kiwimatecoder config subagents show
kiwimatecoder config subagents enable on
kiwimatecoder config subagents max-steps 10
kiwimatecoder config subagents model gpt-5-mini
Or in the REPL: /config subagents [show|enable on|off|max-steps <n>].
Sampling and output styles
Sampling parameters apply to every provider and are sent when set:
kiwimatecoder config sampling set temperature=0.2 top_p=0.9 max_tokens=4096 reasoning_effort=medium
kiwimatecoder config sampling show
kiwimatecoder config sampling reset
Output styles shape the agent's replies: default, concise, explanatory,
or code. Set one with config style set <name> (or /config style set). For
a fully custom instruction, add a system-prompt suffix with
config prompt set "<text>" and remove it with config prompt clear.
Themes, output modes, and accessibility
Control color independently of your terminal, pick a theme, tune how much the agent prints, and switch to ASCII glyphs for screen readers and limited terminals:
kiwimatecoder config ui show
kiwimatecoder config ui color never # auto | always | never
kiwimatecoder config ui theme ocean # default | ocean | magenta | mono
kiwimatecoder config ui output compact # normal | compact | verbose
kiwimatecoder config ui ascii on # on | off
kiwimatecoder config ui spinner off # auto | on | off
The same settings are available in-session with /config ui .... Values live
under the ui key in ~/.kiwimatecoder/config.json:
{
"ui": {
"theme": "ocean",
"color": "auto",
"output_mode": "normal",
"ascii": false,
"locale": "en",
"keybindings": "emacs",
"notify": "off",
"notify_after_seconds": 20,
"spinner": "auto"
}
}
Color precedence: an explicit ui.color of always/never wins; otherwise
NO_COLOR set to anything non-empty disables color, then FORCE_COLOR set to
anything non-empty enables it. With auto and neither variable exported, Rich
still detects a pipe or log file and stays plain.
Output modes shape the tool log. normal prints a line per tool with a success
or failure marker. compact hides successful tool lines while keeping failures,
the thinking status, and the final answer. verbose adds a redacted argument
block (secrets replaced, capped at ~500 characters) before each tool runs and
the result size after.
ASCII mode replaces the check, cross, blocked, folder, and bullet glyphs with
plain text ([ok], [fail], [blocked], no folder prefix, -) and the CLI
confirmations follow suit. Color, theme, ASCII, and output-mode changes apply
to the next session.
Animated status spinners can be disabled for screen readers, tmux capture, or
quiet terminals with config ui spinner off (or /config ui spinner off).
For a fully plain single run, the global --plain flag forces ASCII glyphs, no
color, compact tool output, and no spinner without persisting anything:
kiwimatecoder --plain
kiwimatecoder --plain -p "Summarize this repository"
The full audit — what works today, what does not, and the concrete follow-ups — is in docs/accessibility.md.
Language and locale
A representative subset of user-facing strings is translated: the banner hint,
prompt and approval labels, common errors, /help group titles, and key CLI
messages. Pick the language from ui.locale, the KIWIMATECODER_LANG
environment variable, or English (in that precedence order):
kiwimatecoder config ui locale de # en | de | es
KIWIMATECODER_LANG=es kiwimatecoder # per-run override
The migration is incremental: untranslated strings stay in English, and a
locale that is missing a key falls back to English and then to the key itself.
/config ui locale <en|de|es> switches the language for the current session
immediately.
Keybindings and notifications
The prompt is Emacs-style by default; switch to Vim mode with
config ui keybindings vim (or /config ui keybindings vim). Vim mode keeps
the same completion and Alt+Enter bindings and adds modal editing.
ui.notify can ring the terminal bell (bell) or send a desktop notification
(desktop: OSC 9 when stderr is a TTY, otherwise osascript on macOS or
notify-send on Linux) when a turn takes at least ui.notify_after_seconds
seconds (default 20; 0 notifies after every turn):
kiwimatecoder config ui notify bell
kiwimatecoder config ui notify-after 30
@-mentions
Typing @ offers workspace file-path completions (gitignored files are
skipped). A sent line containing @path/to/file attaches that text file as a
[mentioned files] context block ahead of the message — at most 5 files per
turn, 64 KB each, with truncation markers. Image paths (@shot.png) use the
image-attachment path instead, so pasting or dragging an image into the
terminal works as before.
Model routing
Route short, plain requests to a cheaper model while keeping the session model
for real work. Configure it under model_routing in
~/.kiwimatecoder/config.json:
{
"model_routing": {
"enabled": true,
"simple_model": "gpt-5-mini",
"simple_max_chars": 200,
"exclude_keywords": ["refactor", "implement", "debug", "test"]
}
}
A turn is routed when routing is enabled, simple_model is set, the message is
at most simple_max_chars long, and it contains no code fence, file path,
slash command, or exclude keyword (whole-word, case-insensitive). The override
applies to the primary provider only — fallback providers keep their own
models — and the session's model is never changed.
Prompt caching
Native Anthropic providers support prompt caching. Enable it with
kiwimatecoder config cache on (or /config cache on): requests then send the
system prompt as a cacheable content block and mark the last tool definition as
an ephemeral cache breakpoint, cutting latency and input cost when the same
system prompt and tools repeat across turns. The toggle only changes native
Anthropic payloads — OpenAI-compatible providers cache automatically, so their
requests are byte-for-byte identical either way.
Auto-verify
Point the agent at your test/lint command and it runs automatically after any successful file edit, feeding the output back so it can fix failures:
kiwimatecoder config verify set "pytest -q"
kiwimatecoder config verify show
kiwimatecoder config verify clear
Budgets
Cap a session's spend by tokens, cost, or both. The agent warns at 80% and stops starting new turns once a limit is reached:
kiwimatecoder config budget tokens 500000
kiwimatecoder config budget cost 5.00
kiwimatecoder config budget show
kiwimatecoder config budget clear
A token limit is a whole number from 1 to 1,000,000,000,000,000; use clear
for no limit.
Audit log
Every tool decision (allowed, denied, dry-run, auto-verify) is appended to
~/.kiwimatecoder/audit.log as one JSON line per action. Secrets are redacted
before writing; the file is owner-only and safe to delete.
A pre_tool hook that exits non-zero blocks the action and is recorded with
the hook_blocked decision.
Telemetry and debug logging
Telemetry is opt-in, local-only, and off by default. When enabled, events
from the lifecycle bus (session_start, session_end, pre_tool,
post_tool), provider errors and retries, and (at the debug level) provider
HTTP metadata (method/host/status/duration only — never bodies or headers) are
appended as one compact JSON object per line to
~/.kiwimatecoder/logs/kiwimatecoder.log. Secret-looking strings are redacted
with the same rules as the audit log, the file is owner-only, and it rotates to
.log.1 once it would grow past max_log_bytes:
kiwimatecoder config telemetry enable on
kiwimatecoder config telemetry level info # off | error | info | debug
kiwimatecoder config telemetry show
Slash equivalents: /config telemetry show|enable on|off|level <lvl>. Log
files are never uploaded anywhere. Crash bundles (crash-<timestamp>.json
containing a redacted traceback, version, platform, and recent log lines) are
written only while telemetry is enabled at a level other than off, and
/doctor lists the level, log path, and crash-report count.
Set KIWIMATECODER_DEBUG=1 to force the debug level for one run without
changing config (handy for diagnosing a stubborn provider or proxy issue).
An OTLP exporter is not implemented yet; see the roadmap (5.2 follow-up).
Lifecycle hooks
Run your own shell commands when the agent reaches a lifecycle event. Hooks
live under the hooks key in ~/.kiwimatecoder/config.json (a project
.kiwimatecoder.json may add them too). Each event maps to a list of commands
run with the session workspace as their working directory:
{
"hooks": {
"session_start": ["echo session started in $KIWI_WORKSPACE"],
"session_end": ["echo session ended"],
"pre_tool": ["test \"$KIWI_TOOL_NAME\" != \"run_bash\" || ./scripts/safety-check.sh"],
"post_tool": ["echo \"$KIWI_TOOL_NAME\" exited ok=$KIWI_TOOL_OK\" >> .kiwi-hooks.log"]
}
}
Events are session_start, session_end, pre_tool, and post_tool. Hooks
receive KIWI_EVENT and KIWI_WORKSPACE, plus KIWI_TOOL_NAME,
KIWI_TOOL_OK (true/false), KIWI_TOOL_ARGS (JSON; secrets redacted), and
KIWI_TOOL_DURATION_MS for tool events. A non-zero exit from a pre_tool hook
blocks the tool call; every hook times out after 60 seconds and never crashes
the agent. Commands run through the platform shell (/bin/sh on POSIX,
cmd.exe on Windows), so write them in that shell's syntax; the examples above
are POSIX. /config does not manage hooks yet — edit the JSON directly.
Configuration
Global settings live in ~/.kiwimatecoder/config.json (provider keys, the
default provider, the model chosen for each provider under provider_models,
default mode, sampling, output style, theme/color/output/ASCII preferences,
custom prompt, and persisted tool approvals). The original single-key
~/.kiwimatecoder/config format is read automatically, so existing setups keep
working. Config files from before per-provider models (version 2 or older) are
migrated on load: a model saved with config model set becomes the primary provider's
choice, and a custom provider's default_model becomes its chosen model.
Built-in providers that never had a model chosen ask for one. A custom provider
whose id is now built in (a hand-made kiwimate) is renamed to
kiwimate-custom, keeping its stored key, model, filter, and the profiles that
used it; if it read its key from KIWIMATE_API_KEY, it now reads
KIWIMATE_CUSTOM_API_KEY so the built-in and the custom provider never share a
key.
A project can pin its own settings in .kiwimatecoder.json at the repository
root (or wherever KIWIMATECODER_PROJECT_CONFIG points). Project values
override global config — useful for pinning a provider, model, mode, sampling,
or permissions per repository. A pinned selected_model applies to the primary
provider only and wins over the model chosen for it. API keys are never read
from project files.
A shared team policy file can be layered on top of both (see Team policies and session sharing); it is configured only in the global config, so a cloned repository can never disable or redirect it.
Fetched model catalogs are cached separately in
~/.kiwimatecoder/model_cache.json. It holds no secrets and can be deleted at
any time; the next /model rebuilds it.
Prompt history lives in ~/.kiwimatecoder/history and session autosaves in
~/.kiwimatecoder/sessions/last.json. Both can be deleted at any time.
Run kiwimatecoder doctor (or /doctor) to check config paths, key status,
provider reachability, the model catalog, whether a model is chosen, and the
workspace.
Profiles
Profiles are named presets of global settings: provider, model, mode, sampling,
output style, custom system prompt, verify command, budget, trusted workspace,
command rules, and persisted always approvals. Capture the current effective
settings, then re-apply them anywhere:
kiwimatecoder config profile save work
kiwimatecoder config profile list
kiwimatecoder config profile show work
kiwimatecoder config profile use work # writes the preset into config
kiwimatecoder config profile remove work
Launch once with a profile without persisting it with kiwimatecoder --profile work. On a fresh session the provider, model, mode, and other session-level
settings come from the profile; with --resume/--continue only the mode and
model are overlaid so the restored conversation keeps its provider. Sampling
and budget are global settings, so use config profile use to apply those.
The REPL equivalent is /config profile list|show|save|use|remove.
Cross-machine session sync
Sync saved sessions across machines through a folder you already share (Dropbox, iCloud Drive, a network mount, or a git checkout). There is no server component and nothing is sent anywhere: the feature is off by default and only reads and writes the folder you point it at.
Enable it with an existing directory:
kiwimatecoder sync enable ~/Dropbox/kiwimatecoder
or edit ~/.kiwimatecoder/config.json directly:
{
"sync": {
"enabled": true,
"path": "~/Dropbox/kiwimatecoder",
"machine": "laptop",
"include_autosave": false
}
}
The folder gets a kiwimatecoder-sessions/ subdirectory holding the session
JSON files plus a manifest.json index. machine defaults to a slug of the
hostname; set it explicitly when two machines would otherwise share a name.
kiwimatecoder sync status # local/remote counts, pending changes, conflicts
kiwimatecoder sync push # copy local sessions into the shared folder
kiwimatecoder sync pull # copy newer shared sessions into the local store
kiwimatecoder sync disable # opt out; the shared folder is left alone
The same actions are available in the REPL as /sync [status|push|pull].
Everything mirrors the local session store except the implicit last.json
autosave, which is skipped by default (include_autosave: true opts in) because
it changes on every exit. Unreadable or corrupt files are skipped and reported,
never fatal.
Conflicts. Each machine remembers what it last pushed or pulled. On the next
push, a shared file that changed elsewhere and whose local copy also changed
is kept as both: the shared copy stays put and the local copy is uploaded as
<name>__<machine>.json. Every other difference is last-write-wins by the
session's saved_at timestamp. pull uses the same rule but renames the
incoming file to <name>__<remote-machine>.json instead of overwriting the
local one. Pass --force to push/pull to make the local copy (push) or the
shared copy (pull) win unconditionally.
Team policies and session sharing
Shared team policies
A team can publish a shared policy JSON file (same shape as
.kiwimatecoder.json) that is layered on top of global and project config,
so policy values win. There is no server component and no identity provider:
the file is read from the local path you configure, and a cloned repository can
never disable or redirect it because team settings are taken from the global
config only.
Point the global config at the shared file:
kiwimatecoder config team set-policy ~/team/kiwimatecoder-policy.json
kiwimatecoder config team enforce on
kiwimatecoder config team show
or edit ~/.kiwimatecoder/config.json directly:
{
"team": {
"policy_path": "/Users/you/team/kiwimatecoder-policy.json",
"enforce": true
}
}
The policy file may only control these keys: default_mode,
selected_provider, active_providers, selected_model,
model_filters, command_rules, tool_permissions, sampling, trusted_workspace,
output_style, system_prompt, verify_command, budget, mcp_servers,
plugins, subagents, sandbox, remote, and network. keys, version,
and team are ignored, so a policy can never carry API keys or weaken its own
enforcement. Unknown keys are reported as warnings. The per-provider model
choices (provider_models) are deliberately not a policy key — an enforced
policy would replace every provider's choice at once — so a team pins the
primary provider's model with selected_model.
- Advisory (
enforce: false): policy values override global and project values, but project config still fills in any key the policy does not set. - Enforced (
enforce: true): each policy key replaces the merged value wholesale, and project values for policy keys the policy does not define are ignored, so a repository cannot widen or weaken the policy namespace.
A missing or corrupt policy file never blocks startup: it is skipped and
reported by kiwimatecoder config validate, kiwimatecoder doctor, and
/config team show. The REPL equivalents are
/config team [show|set-policy <path>|enforce on|off].
Session sharing
Share a conversation as a redacted JSON bundle, either as a local file or as a
secret GitHub gist through your own gh login (no token is read or stored
by KiwiMateCoder):
kiwimatecoder share create # last session -> .kiwimatecoder/shares/
kiwimatecoder share create my-session --output ~/Desktop/review.json
kiwimatecoder share create --gist # uploads via `gh gist create`
kiwimatecoder share import bundle.share.json --name from-teammate
In the REPL, /share bundles the current session, /share gist uploads it,
and /share import <path> turns a bundle into a normal saved session.
Privacy notes:
- Every string is passed through the same secret redactor used for logs, so
API keys and
token = ...assignments never leave the machine. - Tool results are omitted (replaced with
[tool output omitted]) unless you pass--include-tool-output; when included they are redacted and truncated to 2 KB. Tool call names are kept for context, and their arguments are redacted and clipped. - Image attachments are replaced with
[image omitted]so no base64 image data is embedded in the bundle. - Bundles are capped at ~256 KB; when a conversation is larger the oldest
messages are dropped and
truncated/truncated_messagesrecord it. - Sharing is local or gist-based only. SSO/identity and any hosted sharing service are deferred (see the roadmap) — there is no server to run.
Config validation
kiwimatecoder config validate checks the stored config and prints a table of
issues, exiting non-zero when any error-level problem is found. It surfaces
exactly what the tolerant getters would silently drop: unknown top-level keys
(warning), malformed provider/model-filter/sampling/budget/hook/command-rule/
profile/MCP/plugin entries, a model chosen for an unknown provider in
provider_models (warning), invalid regexes, unknown hook events, bad network
(proxy/CA/offline) values, bad ACP permission timeouts, a missing or corrupt
team policy file, and bad default mode,
output style, UI (theme/color/ASCII/output mode), or workspace-flag values.
Evals
kiwimatecoder eval runs declarative regression cases against any configured
provider. A case is a small JSON file with a prompt, optional starting files,
and deterministic expectations about the run:
{
"name": "create-file-from-prompt",
"description": "Writes a requested file with exact content.",
"prompt": "Create hello.txt whose contents are exactly 'hello from the eval'.",
"files": {"notes.txt": "Starting workspace file."},
"expect": {
"text_contains": ["hello"],
"text_not_contains": ["error"],
"tools_called": ["write_file"],
"tools_not_called": ["run_bash"],
"files": {"hello.txt": ["hello from the eval"]},
"success": true
}
}
List and run the committed cases:
kiwimatecoder eval list
kiwimatecoder eval run --provider openrouter --model anthropic/claude-sonnet-5
kiwimatecoder eval run --filter create --json --report eval-report.json
Every field in expect is optional: text_contains/text_not_contains check
the final assistant text, tools_called/tools_not_called check the tools the
run used, files maps workspace paths to substrings that must appear in the
file after the run, and success checks the run's own success flag. A run
error is always a failure unless the case explicitly expects success: false.
Cases live in evals/cases/*.json and are discovered sorted by name. Copy
one as a starting point, or point --dir at another directory. The command
exits 0 when every case passes, 1 when any case fails, and 2 on invalid
input (bad directory, malformed JSON, unknown provider, or no --model passed
and none chosen for the provider — No model chosen for <provider>…). Eval
runs call a real model, so they need a configured provider key and a chosen
model (kiwimatecoder setup) or --model; each
case runs in a throwaway temp workspace and nothing is recorded beyond the
report you ask for. Expectations are deterministic — there is no model-graded
scoring yet.
Development
pip install -e ".[dev]"
pytest
ruff check kiwimatecoder tests
mypy kiwimatecoder
Roadmap
The full prioritized plan lives in ROADMAP.md. P0 and P1 are implemented (checkpoints/undo, command rules, dry-run, redacted audit log, hunk-level approvals, todos, ask-user, parallel reads, compaction, auto-verify, budgets, trusted workspace, and message steering with interrupt recovery), and P2 is complete (event bus + hooks, the extensible tool registry, custom commands and prompt templates, on-demand Agent Skills, a plugin system, the MCP client, config profiles with schema validation, per-turn model routing, Anthropic prompt caching, and themes/output modes/NO_COLOR accessibility).
Metadata
Release files for kiwimatecoder 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kiwimatecoder-0.1.0.tar.gz | 682.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kiwimatecoder-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / kiwimatecoder-0.1.0.tar.gz
| Download URL | kiwimatecoder-0.1.0.tar.gz |
|---|---|
| Size | 682.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
780a947e07c72416a2aae88617e4375dbb01f133581a88a58d5e1948cf339699
|
|
BLAKE2b-256 checksum How to use checksums |
3ce27f6b6f267515c0e93b2fcb0b0679a51448fca02f6a5fa8d352ba09ca631d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / kiwimatecoder-0.1.0-py3-none-any.whl
| Download URL | kiwimatecoder-0.1.0-py3-none-any.whl |
|---|---|
| Size | 420.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1b9bc00a8c02ca545e83cfcc58774dadd4b2cdb4e64988ccc845d44cefe7377
|
|
BLAKE2b-256 checksum How to use checksums |
783d18d96604068f69586eaf834597d7635d03635a32d18a74407e587fccfe86
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log