The harness is the CLI that actually runs the turn.
/harness
/harness claude|codex|opencode|telekit|grok
/harness <name> <model> <effort>
/login
/login status
/login cancel
/logout
/model
/model <name>
/model <name> <effort>
/effort
/effort <level>
/ef m
/provider
/provider <name>
/provider <name> <model> <effort>
/provider off
/fanout <prompt>
telekit only sets a harness that is installed on this Mac. A valid name it cannot find is refused and the previous harness stays. A new install uses the harness you picked in the Mac app. If you never picked one, the default is Claude.

Which program is actually running

Bare /harness shows a Program row: the exact binary telekit resolved for the current harness, and the rule that found it — your TELEKIT_*_BIN pin, your PATH, or a well-known install location. If nothing was found it says so. This is the row to read when a harness is installed but turns still fail. Two copies of the same tool on one Mac is common, and the Program row tells you which one answered. If the Telekit harness binary is too old to run a turn, telekit refuses before starting it and names that same path, rather than failing partway through with a message from the tool itself. /harness telekit says it at switch time too: the card carries the warning, the path, and the fix — open the Telekit app → Settings → Reinstall built-in assistant.

Switching harnesses: the handoff

/harness <other> used to start the new harness cold. It no longer does: the switch carries your recent conversation across, so the next message lands on a harness that already knows what you were doing. What carries. The last 20 Telegram-visible exchanges on that lane — your messages and the replies you saw — capped at 8,000 characters in total. Nothing else moves: not files, not running tools, not the other harness’s own memory of the session. When. Only if the harness you are leaving already has a session on this node and thread. If it has none there is nothing to carry, and the switch card says nothing about a handoff. Same-lane round trips are handled too: switch away and back before you say anything and the carry is dropped silently. Where it goes. Once, at the top of your first message to the new harness, labelled as carried context and marked as data rather than instructions. After that the new harness holds it in its own session and it is never injected again. If that first turn fails, the carry stays parked so your retry still has it.

instant and ai

ModeWhat happens
instant (default)The recent conversation is attached to your next message as-is. No extra turn, no waiting.
aiThe harness you are leaving first writes a handoff summary of the conversation (Goal · Done · In progress · Next · Files touched · Open decisions), and the last few exchanges are appended verbatim underneath it.
ai costs one extra turn on the outgoing harness, capped at 120 seconds. It runs after the switch card, so the switch itself is never delayed, and your next message queues behind it. When it lands you get:
✍️ Handoff ready (312 words) from claude.
If it times out, errors, comes back empty, or you /stop it, the switch is unaffected and the carry falls back to instant — out loud, never silently:
Handoff · ai failed (timeout) · using the last 8 exchanges instead.
The reason in the parentheses is timeout, stopped, error or empty.

What the card shows

Bare /harness has a Handoff row with the current mode:
Handoff   `instant`
A switch that carries something adds a row naming what went across:
Handoff   `instant` · 8 exchanges from `claude`
In ai mode that row reads `ai` · writing with `claude`… while the summary is being written.

What drops it

A pending handoff lives in memory only — nothing is written to disk.
  • /new on that lane drops it.
  • Restarting the daemon loses it.
  • A later switch on the same lane replaces it.
Node and thread switches leave it alone: it is keyed to the lane it was staged on.

Changing the mode

telekit config handoff          # show
telekit config handoff ai       # or: instant
The setting is read at every switch — no restart. telekit config show prints the same handoff: line. There is no slash command for it.

All three dials in one line

/harness and /model take the rest of the line as the model and the reasoning effort, so you rarely need three messages:
You sendWhat changes
/model opus xhModel → opus, effort → xhigh
/harness claude opus xhHarness, model and effort
/harness claude fableHarness and model; effort stays as it was
/harness claude xhHarness and effort; model stays as it was
/provider zai glm-5.3 hProvider, model and effort (Telekit)
/provider zai glm-5.2 hOn OpenCode: provider, an OpenCode model, effort
Short effort aliases (l m h xh xx) and full names (low … max) both work. Tokens are read by what they are, not by position, so a bare effort after a harness name is understood. The model and the effort are checked against the harness you are switching to — /harness codex opus is refused, because opus is a Claude model. A line with any bad token changes nothing: you never land half-switched.

Paying for the Telekit harness

The built-in assistant is the Telekit harness. Select it with /harness telekit (sov also works). When telekit ships inside another app, the same harness is listed under that app’s name — telekit still works. Pay with Telekit credits, or with your own OpenRouter key:
ModeWhat you set
credits (default)A Telekit API key from telekit.io/account
openrouterYour OpenRouter API key
telekit lane status            # which mode, and whether its key is set
telekit lane use credits       # or: openrouter
telekit lane set-key           # paste the key for the current mode
/account shows the balance. Top up at telekit.io/account. A Telekit key starts tk_. An OpenRouter key starts sk-or-. Pasting the wrong one is refused there and then. /provider and /model pick the model. Type an OpenRouter id as you see it on openrouter.ai/models — /model qwen/qwen3-coder — or use a short alias (sonnet, telekit-haiku, …) or a /provider slug. The reply’s Serves row names the id that will run. If credits run out, the next message is refused with a top-up link before a turn starts. Keys are stored in the Keychain — never written to a config file.

Where telekit looks for a harness

Bare /harness shows which program will run. Pin TELEKIT_CLAUDE_BIN, TELEKIT_CODEX_BIN, TELEKIT_OPENCODE_BIN, TELEKIT_SOV_BIN, or TELEKIT_GROK_BIN if more than one copy is installed.
HarnessCLIDefault modelEffort
claudeClaude Codeopuslow medium high xhigh max
codexCodexgpt-6.1-sollow medium high xhigh
opencodeOpenCodeglm-5.3default minimal low medium high max
telekitTelekit built-in (sov also works; listed under the host app’s name when bundled)alias set, or any OpenRouter idoff low medium high max
grokGrok Buildgrok-4.7depends on model (max is not on grok-4.5)
Claude aliases: sonnet opus claude-opus-5-5 fable haiku. opus is Claude Opus 5.5 (claude-opus-5-5). fable is Claude Fable 5.1 (claude-fable-5-1). Codex: gpt-6.1-sol gpt-6-astra gpt-6-sol gpt-6-luna gpt-5.6 gpt-5.6-sol gpt-5.6-terra gpt-5.6-luna gpt-5.5 gpt-5.5-codex (extend with TELEKIT_CODEX_MODELS). OpenCode: glm-5.3 glm-5.3-flash glm-5.2 glm-5v-turbo glm-5.1 glm-5-turbo (extend with TELEKIT_OPENCODE_MODELS). Grok: grok-4.7 grok-4.6 grok-4.5 4.7 4.6 4.5 grok. Telekit aliases: sonnet opus haiku openai-gpt openrouter-sonnet telekit-sonnet telekit-haiku telekit-flash — or any OpenRouter model id (vendor/model, e.g. /model qwen/qwen3-coder). /effort short tokens via /ef: l m h xh xx. /effort auto lets Jev pick a level each turn. Independent of /ack. Jev sees this message plus the last few turns, so a short “green light” after a spec is still a build. Store the TypeSafe key with telekit jev set-key or the Mac app Settings › Agent. Missing key → fail closed to the pin. /model auto lets Jev pick haiku / sonnet / opus (or this harness’s small/default/heavy). A clear one-shot stays on the small model. A build or a debug does not stay on the small model. Same spawn call as /effort auto. Same recent-turn context. /intake auto (default) classifies the ask on that spawn. The label is a log line. It does not instruct the agent. /done on stops extra tool rounds. Default off. Setting the same effort already in force does not rewrite.

Signing in and out

/login starts the active harness’s OAuth sign-in and sends the link (and one-time code) over chat. /logout signs it out immediately — no confirmation. Both are owner-only, and with a passcode configured they are refused while the lane is locked.
HarnessFlow
claudeTap the link, sign in, then send the code back as a plain message. telekit finishes the sign-in and deletes your code message from the chat.
codexTap the link, enter the code shown, approve. No reply needed.
grokTap the link and approve — the link already carries the code. No reply needed.
telekitNot applicable — it signs in by API key. See the lane above.
opencodeNot supported.
/login status shows the signed-in state (claude and codex; grok has none). /login cancel abandons a pending sign-in. A pending sign-in expires after 15 minutes and does not survive a daemon restart — run /login again. A successful /login or /logout refreshes the lane’s warm session automatically, so your next message uses the new credentials.

Provider (Telekit and OpenCode)

Refused on Claude, Codex, Grok. /provider takes the rest of the line like /harness does: /provider zai glm-5.3 h sets the lab, the model and the effort in one message. A bad token refuses the whole line — you are never left half-switched. On the Telekit harness the model is scoped to the provider. While /provider zai is set, /model is z-ai’s corner of OpenRouter’s catalog:
  • the Choices line lists that vendor’s models;
  • a bare name resolves inside the scope — /model glm-5.3 means z-ai/glm-5.3 — but only when OpenRouter’s catalog confirms that id. If the catalog cannot be read, name the model in full (/model z-ai/glm-5.3);
  • an effort handle is never read as a model: /model h is refused and points at /effort high;
  • a model from another vendor is refused, and the reply names the way out: “google/gemini-2.5-flash is not a zai model. Pick a zai model, or /provider google first.” Your provider is never switched behind your back;
  • the model you set is the model that runs. The provider’s own default is only the fallback for when you have not picked one inside the scope;
  • switching to a provider your current model does not belong to replaces that model with the provider’s default, and the card says so: Model · z-ai/glm-5.3 (was google/gemini-2.5-flash-lite).
With no provider set, /model is the whole catalog again. On OpenCode nothing is scoped. Its models are its own short names (glm-5.3 …), and /provider there only picks the lab that serves them, so /model behaves exactly as it always has. On OpenCode, native labs run direct and other labs ride OpenRouter with that lab’s default model. /provider off clears the provider — and takes a model and an effort too, on the unscoped menu.

/fanout

The rest of the line is the prompt. The harness splits work onto native subagents. Supported: Claude, Codex, Grok, OpenCode. Not the Telekit harness. Needs a prompt. Refused if a turn is already running.