Chat, code, and agent modes
Chat stays tool-free. Code runs the focused tool loop. Agent plans the work as tasks with real dependencies, routes each one, runs the independent ones concurrently, and synthesizes a single answer that says what failed.
Full capability map
Kolkrabbi is being built one independently tested checkpoint at a time. This page keeps the promise honest: working behavior is separated from settled design and future work.
01 / WORKING
These capabilities exist in the current binary and are covered by the offline test suite. Anything a release has not yet carried to the installer is marked below.
Chat stays tool-free. Code runs the focused tool loop. Agent plans the work as tasks with real dependencies, routes each one, runs the independent ones concurrently, and synthesizes a single answer that says what failed.
low, medium, high, max, and ultra
select the model tier and set the tool-round limit, the shell timeout, and how many tasks an
orchestrated run may open. The older quick/standard/deep words still work.
OpenRouter works today, and an OpenAI-compatible base URL points Kolkrabbi at Ollama,
LiteLLM, vLLM, or another compatible endpoint — used without a key, because the
OpenRouter key is bound to openrouter.ai and is never sent anywhere else. A Claude or
Codex plan answers turns
through the user's own vendor CLI, and /model moves the provider with the
model.
On every start and every login Kolkrabbi asks each connector what it lists today —
codex debug models for Codex, a gateway preview of the Claude families for a
CLI that lists nothing — and only then shows them. /pmodels says how each row
is known: listed, verified once a turn has answered on it,
gone when the vendor stopped listing it, in which case it is refused by name.
Kolkrabbi's own list only ranks; the vendor decides what exists, so a renamed model
tomorrow is a row that changes, not a build that breaks.
/key <key> classifies and masks the value, refuses known subscription
tokens, verifies OpenRouter when reachable, and stores credentials outside config.
Read, list, write, edit, and shell execution cover the code loop, and a sixth asks you a question when the answer is genuinely yours. File paths are confined to the project, three permission tiers — ask, auto-approve, full-auto — decide how much happens without a prompt, and a binary is described rather than sent while a large file says how to page through the rest.
Conversations save atomically and resume. kolk -r resumes the work done in
this directory, and sessions can be searched, renamed, forked, and exported. A session
earns a readable name on its own once enough has happened.
The context window is measured from provider-reported tokens. Compaction fires at a turn
boundary and says what it gave up, /compact undo puts the conversation back,
and a turn refused for length is recovered instead of lost.
KOLKRABBI.md or AGENTS.md in the working directory carries
project instructions, and /remember writes one line of personal guidance
beneath it — only when asked, never as a silent edit to a project file.
In a git repository every turn snapshots the whole working tree into a store outside
it, so /undo takes back a formatter, a codegen step or an rm
that ran through bash — not only Kolkrabbi's own edits. Your index, HEAD,
stash and reflog are never touched. Outside a repository it falls back to copying files
before they change. /diff shows what this session changed, /undo
takes back a turn's files and its conversation together, and /rewind
restores the files alone.
Token, cost, latency, mode, effort, and optional 1–5 ratings stay in local JSONL.
/stats prints the table and /dash serves the same
numbers to a loopback-only page. Neither sends telemetry.
/update finds the newest release, checks its signed checksum before
trusting a byte of it, and replaces the running binary atomically, so an interrupted
update leaves the old one working.
Three identical tool calls returning identical results are a loop, not a fourth attempt.
The call is never made a third time: you are asked whether to run it again, and in
/full-auto the turn stops and says what it stopped. Alternating calls count
too — remove, list, remove, list is a cycle even though no call ever follows itself, and
a nine-call window sees rotations a consecutive counter misses. A failing test whose
output keeps changing is progress and is left alone.
When a decision is genuinely yours — which database, which of two designs — you get a list, not a paragraph. Arrows move, enter takes the highlighted row, the number beside a row takes it outright, escape backs out. The recommendation is first, so enter alone is a real answer. Dismissing is not choosing: it is never reported as picking the first option.
kolk uninstall lists every path it will delete, what each one holds and how
big it is, then asks once. --keep-data spares your key, settings and sessions
for a reinstall. Anything that is not an explicit yes is a no, a closed input included, so
a script can never quietly delete your key.
A turn begins knowing which files differ from the last commit, so advice is about the
tree you actually have. /commit drafts a message from the staged diff and
/pr drafts a title and body — both hand you the command and neither runs it.
/doctor reports keys, directories, terminal and reachability — what it
found, never what it found with. --debug writes a scrubbed log for one
session and tells you where it is, so a bug report can carry it.
kolk sessions and the dashboard mark a session stopped at a permission
prompt, warn when two live sessions share a directory, and show what each has spent. A
bash command that starts a server says which port it took.
A static Go binary, a standard-library-only core, offline end-to-end tests, strict architecture rules, and five target builds protect the working surface.
02 / ACCESS
Every authentication path is built around a hard boundary: Kolkrabbi does not capture or reuse a subscription credential owned by another tool.
/key <key> infers the provider from the key's own shape, and
/key <provider> <key> states it outright for CI or an uncommon
format. Reading the key from stdin keeps it out of shell history.
Kolkrabbi hands sign-in to the user's own unmodified claude CLI and runs it
as a backend: one persistent process per session, scrubbed frames, per-turn cost, and an
effort level that steps down to what the plan actually offers. -P full-auto
reaches the child as the vendor's own permission bypass, said once per session with what it
costs, so a delegated run can execute commands and not only edit files. No subscription
token is stored. Starting a session still expects a gateway key; removing that is an open decision.
Kolkrabbi hands sign-in to the user's own codex CLI and runs it as a
subscription backend. Agent mode gives each subagent its own vendor process while the
session keeps the provider, model, and plan limits visible.
Switching between a gateway model and a subscription plan mid-session keeps the local transcript and project context, moves the provider with the model, and releases the one it retires. An unusable plan model refuses with its reason instead of failing quietly.
/plans lists what each provider plan exposes and /plogin
filters them as you type. Login is handed to the provider's own CLI, never spawned while
Kolkrabbi owns the keyboard, and a clean exit is recorded as unverified until a real turn
proves it. Optional browser login is still planned.
One chain, first hit wins: KOLK_API_KEY, then the provider's own variable from a
short fixed list, then the store, where a manifest routes each key to exactly one backend.
/key --why shows every link, the hit and what it shadowed, masks only. A store
that is locked or unavailable stops with its own remedy and is never read as "no key".
The 0600 file is the default everywhere; the macOS login keychain is opt-in per key
(/key --backend keychain), driven through the system's own
security tool with the command on stdin and every write proven by reading it
back — it protects the key at rest, and buys nothing against code running as you.
03 / CONTINUITY
Only the narrow part of this policy ships today. The rest will prefer explicit, explainable continuation over a silent change in model or billing path.
A provider failure before the stream starts is classified, a temporary 429 is
retried on a bounded schedule, and a free model that is out of capacity rotates to the
next eligible one. Nothing silently changes the model you are paying for.
A subscription limit, an account quota, endpoint capacity, a budget stop, a model
refusal and an unreachable endpoint are told apart, each with the reset time when the
provider gives one, and the
cooldown is remembered per session and per account so other sessions see it too.
/doctor lists what is cooling and when it lifts; the status line says so
while it matters; every limit is one provider.limit event on the wire.
When a model hits a limit, one block says which backend stopped and why, that the turn is kept and when it resumes, and the best equivalent among your configured options with the command that applies it: the best-rated eligible configured model on the same rung of the vendor ladder or one either side, subscriptions first, then paid, then free only if you listed it. What was set aside is named with its reason. Nothing is applied for you.
/continue walks the chain the pause recommended: every equivalent among your
subscriptions, then your paid keys, then the free models you listed, in that order,
skipping whatever is cooling — including a limit another session met, read before each hop —
and setting aside a hop that fails for the next. When one takes, the turn that was waiting
runs on it at the same effort, the hop is printed and published, and nothing about it is
persisted. Or name the one you want: /continue 2.
Off by default: a limit pauses and resumes on the same model, and nothing switches. A free
model never continues a run unless you listed it under continuity.preferred,
whatever else is unavailable. With continuity.select ask, every switch is a
question, once per run: the best equivalent, the next, or pause and resume later, each with
its billing path. The turn is kept whichever you choose.
continuity.mode on with select auto walks the chain by itself under
the same rules the block shows: equivalents only, subscriptions then paid then listed
free, skipping what is cooling, bounded per run, every hop printed and published and none
of it persisted. The turn that hit the limit runs on the next model in the same turn.
Silent auto-switching is never the default.
When the model behind a session hits its allowance, quota or capacity, the session pauses
with the reason and the reset time, keeps the turn that was waiting, and
resumes on its own when the limit lifts, spending no tokens to wait: a monitor inside
Kolkrabbi confirms the lift through key status, /models or the vendor's
sign-in, never a model call. /resume lifts the pause now;
continuity.resume manual waits for it.
04 / WORKFLOWS
Advanced behavior remains optional. The first run stays install, key, and use.
A planned task carries a kind, the kind resolves to a named model slot, and the slot to a model — printed with the plan before anything runs. The orchestrator itself takes a slot too, so planning and synthesis need not use the model that does the work.
/mode agent prints the lane an orchestrated run may spend on —
claude-fable → claude-opus → claude-sonnet → claude-haiku from the top rung —
and trivial work is routed below the ceiling, never above it. A rung that will not open
falls back to the model you selected, announced; nothing signed in below means everything
runs on the ceiling, and the lane says what a sign-in would unlock.
Tasks run three at a time across the dependency graph, and each writing task gets a git worktree of its own, seeded with your uncommitted changes and landed back when it finishes; a change that does not fit is refused, kept, and named. Where git cannot do that, writers take turns in the one tree and the row says why. A failed task is reported instead of discarding the run, the answer says what is missing, and the spend is shown as it goes against an optional ceiling. A dedicated critic is still planned.
A cached live catalog ranks zero-cost, tool-capable models and prefers the strongest coding-oriented one for a session that names no model. A saved model, a flag, or a real effort-tier map still wins, because those are explicit choices.
Include /saga in a normal request to advance one bounded chapter at a time — plan, act, verify,
checkpoint, report — with the project's own tests as the gate, a commit only on green,
and a chapter limit, dollar budget, timeout, and doom-loop detector around it. One request
is one wake: the saga keeps the goal it started with, text that differs becomes a note for
that wake, a saga with nothing left to plan says so, and the next goal archives the finished
artifact beside the new one — no run, resume, status, or stop subcommand exists.
An edit shows its diff before you approve it, @ completes file mentions
against the project, /plan is a read-only mode built out of the permission
rules rather than a second system, and the status line carries context and cost.
/localia reports what this machine can actually run — accelerators, RAM,
free disk — and shows every number behind a fit decision, refusing what does not fit
instead of degrading into swap. A pull asks first, then goes through the Ollama you already
have; kolk never installs one.
Drop review.md in .kolk/commands/ and /review
exists. The body is the prompt, $ARGUMENTS is placed or appended, the
project's file beats your own, and a command cannot take the name of a built-in. An
existing .claude/commands directory is read as-is, so command files you
already wrote work without being moved or converted.
Run a formatter after an edit, a notification at the end of a session. Each command is confirmed once, the permission floor refuses what it always refuses, and a hook that fails or hangs is reported without costing the edit it followed. Hooks declared by a repository are listed in full and confirmed before any of them runs — cloning is never enough to execute anything.
/mcp add <name> <command> names a server; kolk starts it over stdio on
the first turn that needs tools, lists what it offers, and loads the tools that fit under
the schema budget every request pays — the rest are named with their cost. Its tools appear
as name__tool, and allow mcp(name__*) governs one server and
nothing else; without a rule, each call asks. The stdio transport is here; HTTP and the
search-and-load bridge for large servers are still to come.
05 / SAFETY
Safety claims are only useful when architecture and tests can enforce them.
Three tiers are the whole model: ask confirms every change and command, auto-approve edits inside the project but still asks before commands, and full-auto stops asking. No tier removes the floor — credential files, system directories, and unrecoverable commands are refused in all three.
File tools resolve against the project root, symlinks first, and reaching outside asks.
Rules such as allow bash(git *) apply by tool and pattern with last match
winning, kept for this session, this project, or everywhere — and the prompt shows the
rule it would keep before keeping it.
Every tool result is scrubbed at one chokepoint, including secrets that carry no vendor prefix, and credentials move through opaque handles that cannot be printed by accident. Orchestrated work never prompts: what its tier would ask about is refused, with the way to allow it.
Each subagent's network access is decided once — from subagent_network
(auto gives it to research tasks only, on, off),
the task's kind, and whether the vendor's child has a switch at all — and the briefing,
the status line, and the process envelope are all rendered from that one decision. A Codex
child is told both ways; a Claude child has no switch, so it is declared rather than
claimed. Both child paths drop credential-shaped variables, the vendor's own API key
included on purpose, while ordinary build variables survive.
/sandbox on confines the bash tool for the session: Seatbelt on
macOS, Landlock on Linux 5.13 or newer. Writes are limited to the project, its temp
directory and the toolchain caches; credential paths such as ~/.ssh stay
unreadable even inside a widened root; network = deny is optional and is
refused where the kernel cannot enforce it (Linux before 6.7) rather than approximated.
Off by default, so commands keep their normal network access, and the status line always
shows the state. Nine native escape tests run on both platforms; the wrapper costs about
2 ms per command on Linux and 6 ms on macOS.
One versioned envelope, typed payloads, golden frames, and a CI guard that fails a contract change without a changelog entry. CLI, daemon, and future clients read the same bytes; the event vocabulary keeps growing under those rules.
Tests, lint, architecture checks, platform builds, binary-size and startup budgets, installer safety, and release contracts run without spending model credits.
06 / INTERFACES
The terminal remains first. Later clients attach to the same versioned core rather than rebuilding model behavior independently.
Outside a session there are four commands and no more: kolk sessions,
kolk serve, kolk uninstall, kolk help — plus
kolk to open a session and kolk -r to resume one. Everything
else is a /command inside the session, a retired verb says where it went
instead of reaching a model, and kolk help is the front door: what it is,
the build identity line, the licence, both surfaces in full. Scripts still get a one-shot
prompt, strict exit codes, and a streaming JSON output mode.
A persistent multiline composer, live tool and activity status, streamed replies, diffs
rendered line by line before you approve them, @ file completion, and a
status line carrying mode, model, effort, context, and session cost.
Three looks — kolkrabbi, nord, and quiet, which has
no hue of its own — each in a 256-colour and a 16-colour tier chosen by what the terminal
can show. NO_COLOR still wins over every theme. /theme tries one
for the session, /config set theme keeps it, and no file is written until you
ask. A theme changes appearance only: the same words, the same layout, different escapes.
/dash serves a loopback-only page rendered entirely on the server — no
script, no assets, no network — showing spend, tokens, latency, ratings, and recent
sessions with what each one cost. The store stays a plain local file.
kolk serve carries byte-identical event frames over NDJSON, child stdio, and
HTTP server-sent events, with replay from a last-seen event id and a conformance test that
proves the three surfaces agree.
Thin desktop and mobile clients plus complete Windows support arrive as additive frontends and platform ports on top of the protocol and service surfaces above.
07 / REACH
Remote access begins with the bind and the credential, not with the feature. A session you can reach from your phone is a session someone else could reach too.
A wildcard address is not loopback, and serving one without a token is refused before the socket opens. Every route needs the token except two that say nothing, and widening that set now fails a test.
A six-digit code is armed for a couple of minutes, used once, and capped in attempts, on a route that does not exist the rest of the time. This is the server half: pairing is an HTTP call today, and the app that would make it a two-second gesture is below.
Each paired device gets its own token, stored only as a hash, and a device token ranks
below the operator's: it can read the stream, while steering is a separate, higher
grant. /devices lists paired devices, and
/devices revoke <id> withdraws one.
Starting a server prints how to reach it and who else can — the tailnet address first when there is one, the local network named as such when there is not, and the one-line SSH tunnel for a loopback bind.
The server accepts it: a token-gated event stream with replay, and a route that resolves a pending permission request from a device that holds the steering grant. Nothing first-party sends that request yet, so today this is an API you could drive yourself rather than a thing you do from your phone.
Pair a browser with the six-digit code and it gets a page: the session's transcript as a stream that renders as it arrives, and — on a device paired to steer — a box that sends a turn. Server-rendered, no script, installable from the browser's menu where the platform allows. The device's token lives in a cookie scoped to the client, never in a URL; a post is refused unless it comes from the same origin; a device paired to watch is told so and cannot act. The open surface is still exactly two routes.
A paired device sees every session on the machine: which are live, which are blocked on
a prompt and on what, what each has cost, which two share a checkout, and what source
control is doing in a live session's tree — the branch and how many files differ. The same
view is at /dash on the machine. Steering is of the session you paired with;
sending a turn to another session from here is still to come.
08 / WATCH
Two short walkthroughs will live here. Their media sources have not been supplied yet, so these are accessible placeholders rather than broken players.
Install, first key, chat, code, agent, model switching, and local history.
Instalación, primera clave, chat, código, agentes, cambio de modelo e historial local.