Kaku Documentation

A fast, good-looking, AI-friendly terminal for the Mac.

RAW Doc

Technical Documentation: tw93/Kaku

ℹ️ Provenance: Multi-Tier Ingestion Β· CodeWiki Reference

Overview (`README.md`)

Why

Kaku (書く, かく) means "to write" in Japanese. It is a macOS terminal based on WezTerm, with fonts, themes, shell integration, and Mac shortcuts already configured, while preserving full Lua customization.

Kaku is for writing code, alongside Waza (ζŠ€) for engineering habits and Kami (η΄™) for documents.

Quick Start

Download the Kaku DMG, open it, and drag Kaku into Applications. Or install with Homebrew:

bash
brew install --cask kaku

Open Kaku to set up shell integration, install missing optional tools with kaku init, and check your installed version with kaku --version.

Features

  • Ready to use: JetBrains Mono, automatic dark and light themes, copy on select, and familiar Mac shortcuts
  • Tabs and panes: Split your workspace, jump between tabs with Tab Navigator, and restore windows, panes, and working directories when you reopen Kaku
  • Right-click menu: Paste, search, open AI chat, split or close the clicked pane, and open or close tabs without remembering shortcuts
  • Clickable links: Cmd + Click opens URLs and file paths, and URLs automatically wrapped by the terminal keep their full address
  • AI-friendly: See which agent is working and on what at the top right, get notified when Claude Code needs you, and use an optional assistant for command suggestions and chat
  • Remote access: Run kaku remote to get a link, open it in any browser on another computer, and keep using the Kaku on this Mac
  • Shell tools: Built-in zsh completion, syntax highlighting, and directory jumping, with shortcuts for optional Lazygit and Yazi installations
  • Lua configuration: Customize fonts, themes, shortcuts, and terminal behavior using WezTerm's Lua configuration system

Usage Guide

Action Shortcut
New Tab Cmd + T
New Window Cmd + N
Close Tab/Pane Cmd + W
Navigate Tabs Cmd + Shift + [ / ] or Cmd + 1-9
Navigate Panes Cmd + Opt + Arrows
Split Pane Vertical Cmd + D
Split Pane Horizontal Cmd + Shift + D
Open Settings Panel Cmd + ,
AI Settings Cmd + Shift + A
AI Chat Cmd + L
Apply AI Suggestion Cmd + Shift + E
Open Lazygit Cmd + Shift + G
Yazi File Manager Cmd + Shift + Y or y
Clear Screen Cmd + K

Kaku AI

Configure your own AI service with kaku ai to use the built-in assistant. Kaku does not provide or relay the AI service.

  • Command suggestions: When a command fails, the configured assistant can suggest a fix, and Cmd + Shift + E pastes it at the prompt for review
  • Natural language to command: Type # <description> at the prompt and press Enter, and the assistant places the generated command at the prompt for you to review and run
  • Chat: Press Cmd + L to discuss terminal output or work with project files and tools, or run kaku chat from another shell to access the same conversation store
  • AI Tools Config: Manage settings for Claude Code, Codex, Gemini CLI, Copilot CLI, Kimi Code, and more

For authentication, models, API Mode, and tool settings, see the AI assistant docs.

FAQ

  • Is there a Windows or Linux version? Not currently, Kaku is macOS-only
  • How is Kaku different from iTerm2, Warp, Ghostty, or WezTerm? See kaku.fun/compare
  • Can I use transparent windows? Yes, set config.window_background_opacity in ~/.config/kaku/kaku.lua
  • The kaku command is missing. Run /Applications/Kaku.app/Contents/MacOS/kaku init --update-only && exec zsh -l, then kaku doctor

Docs

  • Keybindings - full shortcut reference
  • Features - AI assistant, remote access, lazygit, yazi, remote files, shell suite
  • Configuration - themes, fonts, custom keybindings, Lua API
  • CLI Reference - kaku ai, kaku config, kaku doctor, and more
  • FAQ - common questions and troubleshooting

Background

I heavily rely on the CLI for both work and personal projects. Tools I've built, like Mole and Pake, reflect this.

I used Alacritty for years and learned to value speed and simplicity. As my workflow shifted toward AI-assisted coding, I wanted stronger tab and pane ergonomics. I also explored Kitty, Ghostty, Warp, and iTerm2. Each is strong in different areas, but I still wanted a setup that matched my own balance of performance, defaults, and control.

WezTerm is robust and highly hackable, and I am grateful for its engine and ecosystem. So I built Kaku to be that environment: fast, polished, and ready to work.

Contributors

Big thanks to all contributors who helped build Kaku. Go follow them! ❀️

Support

  • The most direct way to support me is getting Mole for Mac, my paid Mac cleanup app
  • If Kaku helped you, give it a star, share it, or open an issue or PR
  • I have two cats, TangYuan and Coke, and if Kaku has been helpful to you, feel free to treat them to canned food πŸ₯©

These lovely people already did 🐱

License

MIT License. Please feel free to use and contribute to the development. Attribution for WezTerm and the bundled fonts is in NOTICE.md.


Overview (`lua-api-crates/README.md`)

The crates in this directory provide modules and functions
to wezterm's lua config file and interface.

They are registered into the lua config via env-bootstrap.

It is advantageous to build times to have multiple, smaller, crates.


Overview (`term/README.md`)

wezterm-term

This crate provides the core of the virtual terminal emulator implementation
used by wezterm. The home for this
crate is in the wezterm repo and development is tracked at
https://github.com/wezterm/wezterm/.

It is full featured, providing terminal escape sequence parsing, keyboard
and mouse input encoding, a model for the screen cells including scrollback,
sixel and iTerm2 image support, OSC 8 Hyperlinks and a wide range of
terminal cell attributes.

This crate does not provide any kind of gui, nor does it directly
manage a PTY; you provide a std::io::Write implementation that
could connect to a PTY, and supply bytes to the model via the
advance_bytes method.

The entrypoint to the crate is the Terminal
struct.

License: MIT


Overview (`termwiz/README.md`)

Terminal Wizardry

This is a rust crate that provides a number of support functions for
applications interested in either displaying data to a terminal or in building
a terminal emulator.

It is currently in active development and subject to fairly wild sweeping
changes.

Included functionality:

  • Surface models a terminal display and its component Cells
  • Terminal attributes are aware of modern features such as
    True Color, Hyperlinks
    and will also support sixel and iterm style terminal graphics display.
  • Surfaces include a log of Changes and an API for consuming
    and applying deltas. This is a powerful building block for
    synchronizing screen instances.
  • Escape sequence parser decodes inscrutable escape sequences
    and gives them semantic meaning, making the code that uses
    them clearer. The decoded escapes can be re-encoded, allowing
    applications to start with the semantic meaning and emit
    the appropriate escape sequence without embedding obscure
    binary bytes.
  • Capabilities allows probing for terminal capabilities
    that may not be included in the system terminfo database,
    and overriding them in an embedding application.
  • Terminal trait provides an abstraction over unix style ttys
    and Windows style console APIs. Changes from Surface
    can be rendered to Terminals. Terminals allow decoding
    mouse and keyboard inputs in both blocking or non-blocking
    mode.
  • Widget trait allows composition of UI elements at a higher level.
  • LineEditor implements shell-like line editing functionality.

Windows Support

Termwiz understands how to work with both the legacy console APIs and
the new PTY and virtual terminal features available in Windows 10,
allowing for true color terminal applications on Windows 10.

Documentation

https://docs.rs/termwiz


Overview (`crates/bidi/README.md`)

wezterm-bidi - a pure Rust bidi implementation

This crate provides an implementation of the The Unicode Bidirectional
Algorithm (UBA)
in Rust.

This crate was developed for use in wezterm but does not depend on
other code in wezterm.

The focus for this crate is conformance.

This crate is no_std, but does require alloc.

Status

This crate resolves embedding levels and can reorder line ranges.

The implementation conformant with 100% of the BidiTest.txt and
BidiCharacterTest.txt test cases (approx 780,000 test cases).

License

MIT compatible License
Copyright Β© 2022-Present Wez Furlong.

Portions of the code in this crate were derived from the bidiref reference
implementation of the UBA which is:

Copyright Β© 1991-2022 Unicode, Inc. All rights reserved.

See LICENSE.md for the full text of the license.


Overview (`crates/filedescriptor/README.md`)

The purpose of this crate is to make it a bit more ergonomic for portable
applications that need to work with the platform level RawFd and
RawHandle types.

Rather than conditionally using RawFd and RawHandle, the FileDescriptor
type can be used to manage ownership, duplicate, read and write.

FileDescriptor

This is a bit of a contrived example, but demonstrates how to avoid
the conditional code that would otherwise be required to deal with
calling as_raw_fd and as_raw_handle:

text
use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
use std::io::Write;

fn get_stdout() -> Result<FileDescriptor> {
  let stdout = std::io::stdout();
  let handle = stdout.lock();
  FileDescriptor::dup(&handle)
}

fn print_something() -> Result<()> {
   get_stdout()?.write(b"hello")?;
   Ok(())
}

Pipe

The Pipe type makes it more convenient to create a pipe and manage
the lifetime of both the read and write ends of that pipe.

text
use filedescriptor::Pipe;
use std::io::{Read, Write};

let mut pipe = Pipe::new()?;
pipe.write.write(b"hello")?;
drop(pipe.write);

let mut s = String::new();
pipe.read.read_to_string(&mut s)?;
assert_eq!(s, "hello");

Socketpair

The socketpair function returns a pair of connected SOCK_STREAM
sockets and functions both on posix and windows systems.

text
use std::io::{Read, Write};

let (mut a, mut b) = filedescriptor::socketpair()?;
a.write(b"hello")?;
drop(a);

let mut s = String::new();
b.read_to_string(&mut s)?;
assert_eq!(s, "hello");

Polling

The mio crate offers powerful and scalable IO multiplexing, but there
are some situations where mio doesn't fit. The filedescriptor crate
offers a poll(2) compatible interface suitable for testing the readiness
of a set of file descriptors. On unix systems this is a very thin wrapper
around poll(2), except on macOS where it is actually a wrapper around
the select(2) interface. On Windows systems the winsock WSAPoll
function is used instead.

text
use filedescriptor::*;
use std::time::Duration;
use std::io::{Read, Write};

let (mut a, mut b) = filedescriptor::socketpair()?;
let mut poll_array = [pollfd {
   fd: a.as_socket_descriptor(),
   events: POLLIN,
   revents: 0
}];
// sleeps for 20 milliseconds because `a` is not yet ready
assert_eq!(poll(&mut poll_array, Some(Duration::from_millis(20)))?, 0);

b.write(b"hello")?;

// Now a is ready for read
assert_eq!(poll(&mut poll_array, Some(Duration::from_millis(20)))?, 1);

Overview (`crates/vtparse/README.md`)

vtparse

This is an implementation of a parser for escape and control sequences.
It is based on the DEC ANSI Parser.

It has been modified slightly to support UTF-8 sequences.

vtparse is the lowest level parser; it categorizes the basic
types of sequences but does not ascribe any semantic meaning
to them.

You may wish to look at termwiz::escape::parser::Parser in the
termwiz crate if you're looking for semantic
parsing.

Comparison with the `vte` crate

vtparse has support for dynamically sized OSC buffers, which makes
it suitable for processing large escape sequences, such as those
used by the iTerm2 image protocol.


Overview (`deps/cairo/cairo/README.md`)

Cairo: Multi-platform 2D graphics library

https://cairographics.org

What is cairo

Cairo is a 2D graphics library with support for multiple output
devices. Currently supported output targets include the X Window
System (via both Xlib and XCB), quartz, win32, and image buffers,
as well as PDF, PostScript, and SVG file output. Experimental backends
include OpenGL.

Cairo is designed to produce consistent output on all output media
while taking advantage of display hardware acceleration when available
(for example, through the X Render Extension).

The cairo API provides operations similar to the drawing operators of
PostScript and PDF. Operations in cairo include stroking and filling
cubic BΓ©zier splines, transforming and compositing translucent images,
and antialiased text rendering. All drawing operations can be
transformed by any affine transformation (scale, rotation, shear,
etc.).

Cairo has been designed to let you draw anything you want in a modern
2D graphical user interface. At the same time, the cairo API has been
designed to be as fun and easy to learn as possible. If you're not
having fun while programming with cairo, then we have failed
somewhere---let us know and we'll try to fix it next time around.

Cairo is free software and is available to be redistributed and/or
modified under the terms of either the GNU Lesser General Public
License (LGPL) version 2.1 or the Mozilla Public License (MPL) version
1.1.

Where to get more information about cairo

The primary source of information about cairo is its website:

The latest versions of cairo can always be found at:

Documentation on using cairo and frequently-asked questions:

Mailing lists for contacting cairo users and developers:

Roadmap and unscheduled things to do, (please feel free to help out):

Dependencies

The set of libraries needed to compile cairo depends on which backends are
enabled when cairo is configured. So look at the list below to determine
which dependencies are needed for the backends of interest.

For the surface backends, we have both "supported" and "experimental"
backends. Further, the supported backends can be divided into the "standard"
backends which can be easily built on any platform, and the "platform"
backends which depend on some underlying platform-specific system, (such as
the X Window System or some other window system).

As an example, for a standard Linux build similar to what's shipped by your
distro, (with image, png, pdf, PostScript, svg, and xlib surface backends,
and the freetype font backend), the following sample commands will install
necessary dependencies:

  • Debian (and similar):

    • apt-get build-dep cairo
  • Fedora (and similar):

    • dnf builddep cairo

Technically you probably don't need pixman from the distribution since if
you're manually compiling Cairo you probably want an updated pixman as well.
However, if you follow the default settings and install pixman to
/usr/local, your Cairo build should properly use it in preference to the
system pixman.

Supported, "standard" surface backends

image backend (required)

PNG support (preferred)

PDF backend

PostScript backend

SVG backend

  • none

Supported, "platform" surface backends

Xlib backend

xlib-xrender backend

Quartz backend

  • macOS >= 10.4 with Xcode >= 2.5

Windows backend

  • Microsoft Windows 2000 or newer.

XCB backend

Font backends (required)

freetype font backend

Quartz-font backend

  • MacOS X >= 10.4 with Xcode >= 2.5

Windows GDI font backend

  • Microsoft Windows 2000 or newer

Windows DirectWrite font backend

  • Microsoft Windows 7 or newer

Compiling

See the INSTALL document for build instructions.

Licensing

Cairo is released under the terms of either the GNU Lesser General Public
License version 2.1, or the terms of the Mozilla Public License version 1.1.

See the COPYING document for more information.

History

Cairo was originally developed by Carl Worth [email protected] and Keith
Packard [email protected]. Many thanks are due to Lyle Ramshaw without
whose patient help our ignorance would be much more apparent.

Since the original development, many more people have contributed to cairo.
See the AUTHORS document for as complete a list as we've been
able to compile so far.


Cli (`docs/cli.md`)

CLI Reference

Run kaku in your terminal to see all available commands.

kaku ai

Open the AI settings panel inside Kaku. Configure external coding tools (Claude Code, Codex, Gemini CLI, Copilot CLI, Kimi Code, etc.) and Kaku Assistant.

bash
kaku ai

kaku chat

Start Kaku's standalone AI chat from any shell. This is a discoverable alias for the bundled k helper, so it works even when k is not on your PATH.

bash
kaku chat                 # open interactive chat
kaku chat "explain this"  # one-shot prompt

The chat uses ~/.config/kaku/assistant.toml, shares the same conversation and memory files as the Cmd + L overlay, and supports /new, /resume, /clear, /status, /memory, and /exit in interactive mode.

kaku config

Open the Kaku configuration TUI for common settings and Lua overrides. It creates ~/.config/kaku/kaku.lua if it is missing. Inside Kaku, Cmd + , opens the same screen.

bash
kaku config

kaku doctor

Check the Kaku app bundle, PATH entries, and zsh or fish shell integration. Use this first if something feels broken.

Every run also writes a diagnostic bundle to ~/.local/share/kaku/diagnostics/Kaku-Diagnose.zip: the report, logs, recent crash reports, a short sample of a running Kaku, and any GUI stalls Kaku recorded on its own. Home paths, the host name, MAC addresses, serial numbers and credential-looking values are replaced first, assistant.toml is never read, and nothing leaves your Mac. Attach the zip when you report an issue. If Kaku itself is frozen, run kaku doctor from Terminal.app.

bash
kaku doctor
kaku doctor --shell fish       # check fish even when $SHELL points to zsh
kaku doctor --shell fish --fix # repair the selected integration

kaku update

Check for and install the latest Kaku release.

bash
kaku update

kaku reset

Remove Kaku-managed shell and tmux integration, Kaku-managed git delta defaults, selected Kaku state, and managed theme blocks in ~/.config/kaku/kaku.lua. It also deletes Kaku AI memory (soul/ and ai_chat_memory.md), the AI chat onboarding flag, and the backups/ folder in ~/.config/kaku. User-authored Lua outside managed blocks is preserved. Use with caution and run kaku init again if you want shell integration back.

bash
kaku reset
kaku reset --shell fish # use fish for restart and restore guidance

kaku remote

Use this Mac's terminals from a browser on another device, through Kaku's relay. Remote access is off until you turn it on.

bash
kaku remote               # turn remote access on (asks first) and print a pairing link
kaku remote devices       # list paired browsers
kaku remote revoke <id>   # remove a browser; its open sessions end within seconds
kaku remote off           # turn remote access off
kaku remote --reset       # new identity, every paired browser removed

The page is made for desktop browsers for now. Open the link in the browser you want to pair. A link works once, for 10 minutes, so run kaku remote again for each device. After pairing, bookmark the page: the browser keeps its own key and comes back without a new link. What you type and see is encrypted between the browser and Kaku, and the relay only forwards it. Kaku posts a notification when a new browser pairs, and when a paired one returns after a while. kaku doctor shows whether Kaku is connected to the relay.

kaku init

Set up Kaku's shell integration for zsh or fish. When both shells are installed, an interactive run asks which one to configure. Use --shell to make the choice explicit in scripts or when $SHELL does not match your daily shell. Also installs optional CLI tools (Starship, Delta, Lazygit, Yazi) via Homebrew.

bash
kaku init
kaku init --shell fish
kaku init --shell zsh --update-only

If the kaku command goes missing from your shell, restore it with:

bash
/Applications/Kaku.app/Contents/MacOS/kaku init --update-only
exec zsh -l

kaku cli

Interact with the Kaku multiplexer from scripts and external tools.

bash
kaku cli split-pane                          # split current pane
kaku cli split-pane -- bash -c "echo hello"  # split and run a command
kaku cli --help                              # list all subcommands
kaku cli split-pane --help                   # help for a specific subcommand

Useful for integrating Kaku with AI tools or shell scripts that need to open panes or tabs programmatically.


Config Versions (`docs/config-versions.md`)

Config Version History

config_version is a monotonically increasing integer. The single source of truth is
assets/shell-integration/config_version.txt; the release gate
(scripts/check_release_config.sh) requires it to increment on every release, even when
nothing in the schema changed. Do not hardcode the current number in agent guides or
instruction files; read the txt file instead.

Rules for bumping

  • A schema change must update the bundled defaults (assets/macos/Kaku.app/Contents/Resources/kaku.lua),
    user docs, release checks, and migration behavior together, in one change.
  • Only keys that existed in the previous released version need migration code. A feature
    introduced in the current cycle ships its default directly: no migration, no version-gated
    branches, no release-note migration mention. Check with
    git show V:assets/macos/Kaku.app/Contents/Resources/kaku.lua | grep <key>.
  • A bump with no schema change is normal and expected; record why in this file.

History

Version Release Change
v21 - Adds smart_tab_mode. Introduces the optional SmartPrompt value for window_close_confirmation (the bundled default later flipped to SmartPrompt so a stateful pane is no longer dropped silently on Cmd+Q). Accepts the removed language option as a deprecated field for backward compat.
v22 - Adds a precmd guard so the dark-theme comment color override still applies when the user pre-loads fast-syntax-highlighting or zsh-syntax-highlighting in their own .zshrc.
v23 - Flips the bundled smart_tab_mode default to suggestion_first so Tab accepts a visible autosuggestion, falling back to completion. No schema change, so no migration; users who set completion_first keep it.
v24 - Migrates $schema keys in user yazi configs to the #:schema comment form that yazi 26.5.6+ requires. No schema change; the repair runs in three places that must stay in sync: setup scripts, the yazi wrapper, and kaku.lua.
v25 - No schema change. Bumps so an updated install regenerates the bundled zsh integration, picking up the fast-syntax-highlighting path-to-dir style that no longer underlines existing directories.
v26 V0.12.4 No schema or bundled-integration change; increments only because the release gate requires a bump every release. The release highlight reuses the Cmd+Click-opens-links improvement.
v27 V0.13.0 Adds tab_title_show_foreground_process, an opt-in setting for showing foreground process names in auto-generated tab titles. No migration is needed because this key did not exist in V0.12.4.
v28 - No schema change. Bumps so existing installs regenerate the bundled zsh integration with the self-contained SSH wrapper required by shell snapshot tools.
v29 V0.15.0 No schema change. Bumps so existing installs regenerate the bundled shell integrations with the aligned ssh wrappers: fish keeps user-defined ssh functions and gains the 1Password fix, env-prefix ssh aliases work, and mosh gets the same TERM fallback.
v30 V0.16.0 No schema change. Bumps so existing installs regenerate shell integrations that authenticate inline AI control messages with a local capability before terminal output can trigger assistant requests, and that scope the Starship prompt setup to Kaku instead of every zsh.
v31 V0.17.0 Adds the optional file_link_editor setting for choosing which editor opens local terminal file links, bare-domain Cmd+Click links (e.g. github.com without a scheme), and Option+Click cursor movement within the current input line. Also regenerates shell integrations with the #511 fixes: the inline AI capability file is read tolerantly (zsh/fish read treat a missing trailing newline as EOF failure), user-var guards report failure with return 1 instead of masking it, and the fish widget only enters the waiting state after the request was actually emitted. The Rust side also writes the capability file with a trailing newline for new installs.
v32 V0.18.0 No schema change, and no bundled-integration change either; increments only because the release gate requires a bump every release. The release highlights reuse the new Move Tab to New Window command and the multi-display menu bar clamp fix.
v33 V0.19.0 No schema change. Bumps so existing installs pick up two bundled fixes: light-theme selected rows keep a visibly blue background instead of washing out to near-white, and the lazygit launcher resolves its working directory from the shell that actually receives the input, so it also works inside nested shells.
v34 V0.20.0 No schema change. Regenerates shell integrations to reset mouse reporting at the prompt after abnormal TUI or SSH exits, preserve the Kaku prompt and Smart Tab in tmux, and correct fish grep completion expansion.
v35 V0.21.0 No schema change. The config generated on first launch now sets color_scheme = 'Kaku Dark'; existing configs keep the bundled default that follows macOS appearance, so no migration is needed. Also increments because the release gate requires a bump every release.
v36 V0.22.0 Adds the opt-in tab_title_use_pane_title key and the opt-in BuiltinInsert value for ime_preedit_rendering; both defaults are unchanged. The bundled show_new_tab_button_in_tab_bar now defaults to true, and configs that set it keep their value, so no migration is needed. Bumps so existing installs regenerate kaku.zsh and stop writing before the first prompt (#561).
v37 V0.23.0 Adds the macos_global_hotkey_* keys (mode, height_percent, animation_duration_ms, hide_on_focus_loss, extend_behind_notch, follow_mouse, appearance, padding); mode defaults to the new Drawer, and Ordinary keeps the previous show and hide. All are new in this cycle, so no migration. Bumps so existing installs rerun setup, which replaces a ~/.config/starship.toml still identical to the V0.10.0 to V0.22.0 copy whose icons were blank (#573).
v38 V0.23.1 No schema change. Bumps so existing installs regenerate the shell integrations: the cursor comes back at the prompt after a program hides it and exits, and dotfiles kept as symlinks stay linked when Kaku updates them.
v39 V0.24.0 No schema change: the remote keys already existed in V0.23.1, and remote access stays off by default. Increments because the release gate requires a bump every release; the highlight introduces kaku remote.
v40 V0.25.0 Adds show_agent_title (default true), which is new in this release, so no migration is needed. Bumps so existing installs regenerate kaku.zsh, which loads the completion dump from cache again and refreshes it after a successful full check, and pick up the Yazi init.lua that leaves a row under the path when none exists.
v41 V0.26.0 No schema change. Increments because the release gate requires a bump every release; the highlights cover the remote page's fonts and agent title, and the character picker's return to the command palette.
v42 V0.26.1 No schema change. Increments because the release gate requires a bump every release; the highlight covers Restart to Update installing the new version.

When you bump the version, add a row here in the same change.


Configuration (`docs/configuration.md`)

Configuration

Config File

Kaku creates ~/.config/kaku/kaku.lua with a commented template on first launch, and kaku init or kaku config recreate it if it is missing. Open it with kaku config or Cmd + ,.

The file loads the bundled Kaku defaults first, then applies your overrides on top:

lua
local wezterm = require 'wezterm'

local function resolve_bundled_config()
  local resource_dir = wezterm.executable_dir:gsub('MacOS/?$', 'Resources')
  local bundled = resource_dir .. '/kaku.lua'
  local f = io.open(bundled, 'r')
  if f then f:close(); return bundled end
  return '/Applications/Kaku.app/Contents/Resources/kaku.lua'
end

local config = {}
local bundled = resolve_bundled_config()
if bundled then
  local ok, loaded = pcall(dofile, bundled)
  if ok and type(loaded) == 'table' then config = loaded end
end

-- User overrides:
config.font_size = 16
config.window_background_opacity = 0.95

return config

The generated file is a longer version of this, with commented examples below -- User overrides:; most users only need to uncomment the lines they want to change.

Common Overrides

Add only the settings you want to change:

lua
config.font_size = 16
config.window_background_opacity = 0.95

-- New installs start with config.color_scheme = "Kaku Dark". Change it to:
-- config.color_scheme = "Kaku Light"
-- config.color_scheme = "Auto"  -- follow macOS appearance

Keep terminal behavior, appearance, key bindings, launch behavior, and other WezTerm-compatible settings in kaku.lua.

Manage Kaku Assistant settings with kaku ai. That command writes ~/.config/kaku/assistant.toml for model, base URL, auth, API keys, and tool settings. The Lua/TOML split is intentional: kaku.lua stays compatible with WezTerm-style terminal configuration, while assistant.toml is managed by the AI setup flow.

Appearance

Theme

New installs start in Kaku Dark, because the generated kaku.lua sets config.color_scheme = "Kaku Dark". Installs whose config has no color_scheme line keep following macOS appearance, switching between Kaku Dark and Kaku Light automatically. To follow macOS appearance, choose Auto in kaku config or remove the config.color_scheme line. To force one theme:

lua
config.color_scheme = "Kaku Dark"   -- always dark
config.color_scheme = "Kaku Light"  -- always light

Color overrides

Remap specific hex colors to keep theme consistency with apps that output their own colors. color_overrides applies to rendered backgrounds, including palette-backed ANSI backgrounds and truecolor backgrounds. foreground_color_overrides applies only to truecolor text:

lua
config.color_overrides = {
  ['#6E6E6E'] = '#3A3942',
}

config.foreground_color_overrides = {
  ['#FFFFDB'] = '#575653',
}

Font

Kaku defaults to JetBrains Mono with PingFang SC as CJK fallback. Change font:

lua
config.font = wezterm.font("Fira Code")

Kaku disables ligatures by default. Re-enable:

lua
config.harfbuzz_features = {}

Font size

Kaku auto-selects 15px (low-res) or 17px (high-res) based on your display. Override:

lua
config.font_size = 16

Line height

lua
config.line_height = 1.28  -- default

The default favors readable text spacing. Character-cell graphics (QR codes, neofetch logos, TUI charts) stretch with the row height; set 1.0–1.1 if you want them near-square. See the FAQ for details.

Window transparency

lua
config.window_background_opacity = 0.92
config.macos_window_background_blur = 20  -- optional blur (0–100)

Traffic lights (macOS)

By default, Kaku embeds the macOS traffic light buttons into the tab bar area using INTEGRATED_BUTTONS|RESIZE. To hide the traffic lights while keeping resize edges and tab-bar dragging:

lua
config.window_decorations = "RESIZE"

RESIZE preserves the ability to resize the window from its edges and drag it by the tab bar; it only removes the close/minimize/zoom buttons.

Agent title

While Claude Code, Codex or Kimi runs in the active pane, its mark and current topic show at the top right of the window, and at the right end of the remote access page's tab bar. To turn it off, choose Off for Agent Title in kaku config, or:

lua
config.show_agent_title = false

Padding

lua
config.window_padding = { left = '24px', right = '24px', top = '40px', bottom = '20px' }

Sizes accept px, pt, cell, and %. px is a physical pixel value and does not scale with display DPI, so the same value can look smaller on a high-density display. Use pt for DPI-scaled spacing or cell for spacing relative to the terminal cell size, for example top = '15pt'.

Terminal Behavior

Cursor

lua
config.default_cursor_style = "BlinkingBar"
config.cursor_thickness = "2px"
config.cursor_blink_rate = 500

Scrollback

lua
config.scrollback_lines = 10000  -- default

File link editor

Set an editor command for local file links printed in the terminal. Kaku appends the resolved path, or path:line:column when the link includes a location. Shell-style quoting is supported for command arguments:

lua
config.file_link_editor = "zed"
-- config.file_link_editor = "cursor --goto"

This setting takes priority over Kaku's automatic VS Code detection. When it is unset, Kaku keeps the existing VS Code and $VISUAL / $EDITOR fallback behavior.

Copy on select

Enabled by default. Disable:

lua
config.copy_on_select = false

Strip leading whitespace on copy

When copying indented multi-line text (e.g. from a code block), remove the shared leading whitespace so the pasted result starts at column 0:

lua
config.copy_strip_leading_whitespace = true  -- default: false

Restore previous session

Re-open the tabs and panes from your last session on launch. Enabled by default; set it to false to disable saving and restoring the session:

lua
config.restore_previous_session = false  -- default: true

Working directory inheritance

lua
config.window_inherit_working_directory = true   -- new windows
config.tab_inherit_working_directory = true       -- new tabs
config.split_pane_inherit_working_directory = true -- new splits

Focused pane emphasis

To make the focused pane easier to spot, adjust the colors of inactive panes:

lua
config.inactive_pane_hsb = {
  hue = 0.95,
  saturation = 1.0,
  brightness = 0.9,
}

Each value multiplies the pane's existing HSV component, so 1.0 leaves that component unchanged. hue is not a color value or a degree-based rotation; small adjustments work best. The focused pane itself is not transformed.

Tab bar

Hidden when only one tab is open. Auto-generated tab titles show the current directory by default. You can change the position, shorten path titles, or opt into showing the foreground command alongside the path:

lua
config.tab_bar_at_bottom = false                   -- move to top
config.tab_title_show_basename_only = true         -- show "dirname" instead of "parent/dirname"
config.tab_title_show_foreground_process = true    -- show "dirnameΒ·codex" while commands run
config.tab_title_use_pane_title = true             -- show application titles set via OSC 0/2
config.show_tab_index_in_tab_bar = true            -- number tabs: "1:dirname", "2:dirname"

show_tab_index_in_tab_bar (Settings: Tab Numbers) prefixes each tab with its position, so Cmd + 1 through Cmd + 8 select the tabs numbered 1 to 8. Cmd + 9 always selects the last tab, whatever its number.

With tab_title_use_pane_title, the active pane's title also supplies the window title and the title of a split tab. Explicit tab renames still take precedence. Shell prompt hooks may overwrite application titles after a command exits; this is independent of OSC support.

The trailing cell stays blank until a pane wants your attention, then shows an amber dot. Background tabs that emit BEL use it, so does any program that reports an error or paused state through the OSC 9;4 progress sequence, and so does Claude Code when it waits on you, finishes or fails (OSC 7501). Disable only the BEL part if you do not want tab-level bell notifications:

lua
config.bell_tab_indicator = false

Scrollbar

Disabled by default. Enable via kaku config (toggle the scrollbar style option) or in Lua:

lua
config.enable_scroll_bar = true

If you want the mouse wheel to scroll inside alternate-screen apps such as nano and vim, instead of peeking into Kaku's primary scrollback, enable:

lua
config.alternate_screen_wheel_scrolls_terminal = true

Selection drag + mouse wheel

Controls what the mouse wheel does while you are dragging out a selection with the left mouse button held down. Defaults to "Extend", which matches macOS NSTextView apps such as Safari, TextEdit, VS Code, iTerm2 and Terminal.app: the wheel scrolls the scrollback and the selection grows to follow the cursor across screens.

lua
-- Default (recommended): scroll AND extend the selection so you can grab
-- text that spans more than one screen of output.
config.selection_wheel_scroll_behavior = "Extend"

-- Scroll the scrollback but leave the selection range untouched.
config.selection_wheel_scroll_behavior = "ScrollOnly"

-- Drop the wheel event entirely (the old behavior);
-- selecting text that does not fit on one screen requires releasing the
-- mouse, scrolling, and re-selecting.
config.selection_wheel_scroll_behavior = "Ignore"

macOS Option key

Left Option sends Meta (useful for Vim/Neovim word navigation). Right Option sends compose characters.

lua
config.send_composed_key_when_left_alt_is_pressed = false  -- default: left = Meta
config.send_composed_key_when_right_alt_is_pressed = true  -- default: right = Compose

Updates

Kaku checks GitHub for new releases in the background (enabled by default) and quietly downloads a newer version when it finds one. It never installs on its own: it shows a notification, and clicking it asks you to confirm first, since applying an update closes every window and stops running tasks.

Turn off background checks entirely:

lua
config.check_for_updates = false

Change how often it checks (default 10800, i.e. every 3 hours):

lua
config.check_for_updates_interval_seconds = 86400  -- once a day

You can always update manually with kaku update or from the app menu, regardless of these settings.

Custom Keybindings

Always insert into config.keys, never replace it. Replacing erases all Kaku defaults.

lua
-- Navigate pane right
table.insert(config.keys, {
  key = 'RightArrow',
  mods = 'CMD|SHIFT',
  action = wezterm.action.ActivatePaneDirection('Right'),
})

-- Split pane horizontally
table.insert(config.keys, {
  key = 'Enter',
  mods = 'CMD|OPT',
  action = wezterm.action.SplitHorizontal({ domain = 'CurrentPaneDomain' }),
})

Full list of available actions: WezTerm KeyAssignment reference.

Advanced

Enterprise proxy headers

Add custom HTTP headers to Kaku Assistant API requests (for corporate proxies or API gateways):

toml
# ~/.config/kaku/assistant.toml
custom_headers = ["X-Customer-ID: your-id", "X-Org: your-org"]

Note: Authorization and Content-Type are reserved and cannot be overridden.

Extend Command Palette

Add a custom command to Command Palette (Cmd + Shift + P) via kaku.lua:

lua
wezterm.on('augment-command-palette', function(window, pane)
  if not pane then return {} end

  local cwd_obj = pane:get_current_working_dir()
  if not cwd_obj then return {} end

  -- Finder can only reveal local paths. file_path is already URL-decoded,
  -- so directories containing spaces or non-ASCII characters work too.
  local host = cwd_obj.host
  if cwd_obj.scheme ~= 'file'
      or (host and host ~= '' and host ~= 'localhost' and host ~= wezterm.hostname():lower()) then
    return {}
  end
  local cwd = cwd_obj.file_path
  if not cwd then return {} end

  return {
    {
      brief = 'Reveal in Finder',
      doc = 'Reveal current directory in Finder',
      action = wezterm.action_callback(function()
        wezterm.run_child_process({ 'open', '-R', cwd })
      end),
    },
  }
end)

Full WezTerm Lua API

Kaku uses WezTerm's configuration system. Any WezTerm config option works in kaku.lua. For the complete reference, see:

IME composition

To keep the character after the cursor visible when composing Korean, Japanese or Chinese text in the middle of a line:

lua
config.ime_preedit_rendering = 'BuiltinInsert'

This shifts the remaining cells of the current row for display only and clips at the pane edge. The terminal buffer and bytes sent to the application stay unchanged. The default Builtin mode overlays the preedit; System does not select native preedit rendering on macOS.


Faq (`docs/faq.md`)

FAQ

Is there a Windows or Linux version?

Not currently, Kaku is macOS-only.

How is Kaku different from iTerm2, Warp, Ghostty, or WezTerm?

Kaku is a WezTerm-based Mac terminal with fonts, themes, tabs, panes, and shell tools already set, plus an optional assistant that uses the AI service you configure. See the comparison on the website: https://kaku.fun/compare

Can I use a transparent window?

Yes. Add these lines below -- User overrides: in ~/.config/kaku/kaku.lua, which already loads the bundled defaults into config and returns it:

lua
config.window_background_opacity = 0.92
config.macos_window_background_blur = 20  -- optional blur, 0–100

How do I turn off copy on select?

lua
config.copy_on_select = false

How do I customize keybindings?

Append to config.keys, do not replace it, as shown in keybindings.md. configuration.md has more examples.

Can I control working directory inheritance?

Yes, individually for windows, tabs, and splits:

lua
config.window_inherit_working_directory = true
config.tab_inherit_working_directory = true
config.split_pane_inherit_working_directory = true

All are enabled by default.

How do I disable Kaku Assistant?

Run kaku ai, open Kaku Assistant settings, and set Enabled to Off. Or edit ~/.config/kaku/assistant.toml directly:

toml
enabled = false

How do I use a custom LLM provider?

Run kaku ai, keep Auth Type set to api_key, and enter your Base URL, API Key, Simple Model, and Deep Model manually. Choose API Mode chat_completions for /v1/chat/completions, or responses for /v1/responses. If the Responses provider supports hosted search, set Native Web Search to On; no separate search provider or search API key is required.

How do I restore default config?

Run kaku reset. It removes Kaku-managed integration and state, including Kaku AI memory and the backups/ folder, while user-authored Lua outside managed blocks is preserved; see cli.md for the full list. Run kaku init again if you want shell integration back.

The `kaku` command is missing. How do I recover it?

bash
/Applications/Kaku.app/Contents/MacOS/kaku init --update-only
exec zsh -l

Then run kaku doctor to verify everything is healthy.

How do I use Kaku's CLI from scripts?

bash
kaku cli split-pane
kaku cli split-pane -- bash -c "echo hello"
kaku cli --help

See cli.md for full reference.

How do I enable the scrollbar?

Open kaku config and toggle the scrollbar option, or add to ~/.config/kaku/kaku.lua:

lua
config.enable_scroll_bar = true

How do I scroll inside nano, vim, or another full-screen terminal app?

Enable alternate-screen wheel forwarding:

lua
config.alternate_screen_wheel_scrolls_terminal = true

How do I change the font? My font change isn't taking effect.

Font changes require explicitly setting config.font in your config:

lua
config.font = wezterm.font('Your Font Name')

Note: Kaku's theme-aware font weight system only applies to the default JetBrains Mono stack. Once you set a custom font, Kaku will no longer override its weight automatically.

My `window_padding` change isn't working.

window_padding takes a number or a string with a unit. Plain numbers are pixels, so 24 and '24px' mean the same thing, and the other units are 'pt', '%', and 'cell':

lua
config.window_padding = { left = '24px', right = '24px', top = '40px', bottom = '20px' }

The screen jumps to the top while Claude Code is generating output.

Since V0.12.1 the viewport no longer jumps to the top during streaming output. If you scroll up mid-stream, pressing the down arrow or scrolling back down returns you to the current output.

Cmd+Shift+Y sends a local path when inside an SSH session.

The yazi remote-files feature (Cmd+Shift+R) is designed for SSH sessions and mounts the remote filesystem via sshfs. Cmd+Shift+Y is for local yazi. Use Cmd+Shift+R when you are inside an SSH pane.

Kaku's prompt shows up in other terminals, or is missing from them.

Kaku's shell integration is loaded by every zsh and fish, but the Starship prompt and Smart Tab only start inside Kaku, including tmux sessions started from Kaku. Other terminals keep whatever prompt you already had.

If you use Kaku's Starship as your one prompt everywhere, add this before the Kaku line in your .zshrc (set -gx KAKU_PROMPT_EVERYWHERE 1 in config.fish):

sh
export KAKU_PROMPT_EVERYWHERE=1

Smart Tab stays Kaku-only; KAKU_SMART_TAB_DISABLE=1 turns it off.

The `y` shell wrapper doesn't sync my directory on exit.

Make sure the Kaku fish/zsh shell integration is sourced. Check with kaku doctor. The y wrapper requires the shell init to be loaded. A bare yazi call will not sync the directory.

How do I install or update Kaku with Homebrew?

Install the official cask:

bash
brew install --cask kaku

Homebrew-managed installs update with brew upgrade --cask kaku, or with kaku update (it detects the cask).

If you still have the older tap tw93/tap/kakuku, keep upgrading that tap, or move to the official cask:

bash
brew uninstall --cask tw93/tap/kakuku
brew install --cask kaku

Claude Code or Codex notifications don't appear.

First check that macOS allows them: choose Kaku > Notification Settings... and turn on Allow Notifications. macOS never asks again after a denial, so when a notification gets dropped for this reason Kaku tells you the next time you switch back to it.

Claude Code 2.1.295 and later tell Kaku whether they are working, waiting on you or done through the program status protocol (OSC 7501), and Kaku turns waiting, done and errors into a notification and the tab's attention dot with no setting needed. Check with claude --version, and leave preferredNotifChannel at its default auto, since ghostty there makes Claude Code post a second notification of its own. Older versions only notify terminals they recognize and send nothing to Kaku, so on those set this in ~/.claude/settings.json:

json
{ "preferredNotifChannel": "ghostty" }

Codex works without changes: it rings the terminal bell and Kaku turns that into a notification. To see Codex's own message instead of a generic one, add this to ~/.codex/config.toml:

toml
[tui]
notification_method = "osc9"

Notifications appear while Kaku is in the background, not for the pane you are looking at.

How do I change the global hotkey?

Cmd + Opt + Ctrl + K shows or hides Kaku from any app. It follows your current keyboard layout, so on Colemak or Dvorak it is whichever key types K. To pick another combination, change Global Hotkey in kaku config, or set it in Lua:

lua
config.macos_global_hotkey = { key = 'j', mods = 'CMD|OPT|CTRL' }

By default (macos_global_hotkey_mode = 'Drawer'), the hotkey creates a dedicated terminal session on first use, then shows or hides that same session. Ordinary windows and their running tasks are not moved or hidden. The top-down drawer starts at the screen's top edge, covers the menu bar, and spans the display width and one third of its height. It has no native title bar, traffic-light buttons, or window-rounded corners. Opening Kaku from the Dock opens ordinary windows, not the drawer. The drawer is not restored as an ordinary window after restarting Kaku, and its geometry does not overwrite ordinary window geometry. Use macos_global_hotkey_mode = 'Ordinary' to toggle the selected ordinary window instead of invoking the dedicated drawer: Kaku selects the key ordinary window, then the main ordinary window, then the first available ordinary window, or creates one if none exists. This mode does not hide the entire application or toggle every window.

To reveal the hotkey window on the display containing the mouse pointer:

lua
config.macos_global_hotkey_follow_mouse = true

This defaults to false, preserving AppKit's main-display behavior. The display is chosen each time the hotkey reveals the window; moving the pointer does not move a visible window, and hiding it does not move it to another display. If no display contains the pointer, Kaku falls back to the main display.

Inherited appearance and drawer overrides

The drawer inherits the ordinary base configuration, including font, theme, opacity, blur, tab bar, scrollbar, and window_padding. This is configuration inheritance, not a copy of a particular ordinary window's live session, position, fullscreen state, or font zoom. Ordinary title-bar spacing does not apply to the drawer.

Set only the appearance fields you want to differ:

lua
config.macos_global_hotkey_appearance = {
  font_size = 16,
  window_background_opacity = 0.85,
  macos_window_background_blur = 28,
  hide_tab_bar_if_only_one_tab = true,
}

Supported appearance fields are font, font_rules, font_size, line_height, color_scheme, colors, window_background_opacity, text_background_opacity, macos_window_background_blur, window_frame, enable_tab_bar, hide_tab_bar_if_only_one_tab, tab_bar_at_bottom, use_fancy_tab_bar, and enable_scroll_bar. Omitted fields, or fields set to nil, inherit the base configuration. Explicit false and 0 are overrides, not inheritance markers. Color overrides preserve unspecified base color fields; font rules and window frames use their usual replacement semantics.

Drawer content padding can be overridden one side at a time. For example, to use compact padding without changing ordinary windows:

lua
config.macos_global_hotkey_padding = {
  left = '16px', right = '16px', top = '8px', bottom = '8px',
}

These values are an example, not separate product defaults. Omitted sides inherit the corresponding window_padding side, so { top = 0 } changes only the top. Set macos_global_hotkey_padding = nil to restore inheritance. The same units as window_padding are supported (px, pt, %, cell); percentages are evaluated against the current drawer's full dimensions. Zero disables that side's content padding (an enabled scrollbar still reserves one cell when right padding is zero).

Base configuration reloads update inherited fields, and removing an override restores inheritance. Explicit per-window overrides from window:set_config_overrides() take precedence over the drawer appearance layer. Drawer font zoom is stored separately from ordinary-window zoom; an explicit drawer font_size takes precedence over saved drawer zoom when the window is created. Changing the configured drawer font size resets its live zoom without changing ordinary-window zoom.

Drawer behavior

These behaviors have drawer-specific defaults rather than inheriting ordinary-window geometry:

lua
config.macos_global_hotkey_height_percent = 100 / 3
config.macos_global_hotkey_animation_duration_ms = 200
config.macos_global_hotkey_hide_on_focus_loss = true
-- Inherit macos_fullscreen_extend_behind_notch unless explicitly set:
-- config.macos_global_hotkey_extend_behind_notch = false

Height is a percentage of the physical display frame in the range (0, 100]. The drawer remains full-width and top-aligned. Animation duration is in milliseconds, from 0 (no animation) to 10000; the macOS Reduce Motion setting always disables animation. Turning off focus-loss hiding pins the drawer until you hide it with the hotkey.

On a notched display, Kaku adds the current display's safe-area height above the content; external displays without a notch get no extra menu-bar clearance. This safe area is separate from configured top padding, including when top is zero. macos_global_hotkey_extend_behind_notch = false enables notch clearance independently of ordinary fullscreen windows; true disables it. When omitted, it inherits macos_fullscreen_extend_behind_notch. Moving the drawer to another display or unplugging it recalculates the safe area. None of these settings changes the system menu bar or display configuration.

QR codes and terminal graphics look vertically stretched.

Kaku's default line_height = 1.28 favors comfortable text spacing. Terminal graphics built from characters, such as QR codes, neofetch logos, and TUI bar charts, scale with the row height, so they render about 28% taller than in terminals with no extra line spacing. This is a typography trade-off, not a rendering bug: block characters must fill the whole cell so TUI borders and progress bars stay seamless.

If you want near-square graphics, lower the line height in ~/.config/kaku/kaku.lua:

lua
config.line_height = 1.1  -- or 1.0 to match terminals without extra spacing

Note that no terminal renders half-block QR codes perfectly square: with common monospace fonts the cell is naturally a bit taller than 2:1 even at line_height = 1.0.

Can I use Kaku with tiling window managers (yabai, AeroSpace)?

Kaku is compatible with yabai and AeroSpace. If you see continuous flickering, it is usually caused by the tiling WM fighting with Kaku's fullscreen/resize logic. Disabling Kaku's native fullscreen (config.native_macos_fullscreen_mode = false) or excluding Kaku from the tiling WM's managed window list typically resolves it.

How do I use Kaku through a phone or tablet remote desktop?

Hold anywhere for about half a second, then lift, to open the menu a right click would: on a tab you get New Tab, Tab Navigator and Close Tab, and on the terminal you get Copy, Paste, Split and the rest. This works in every window, as long as the remote client forwards a held press as a held left button, which UU does. In panes where a program such as vim or tmux takes mouse input, the hold stays with that program.

Window > Touch Mode adds a close button to every tab, since a finger has no hover. The tab bar keeps its height and look, and the terminal font and line height do not change.

Is remote access free?

Yes. I pay for the relay server myself, as a thank-you to everyone who has been building Kaku in the open with me. Your privacy does not rest on trusting that server: what you type and see is encrypted between the browser and Kaku, so the relay only forwards data it cannot read. It is a server that does this one job, so the connection stays quick.

The remote web page says the Mac is offline, or asks me to pair again.

The page reaches your Mac through Kaku, so the Mac has to be awake with Kaku running and remote access on. On a laptop, keep it plugged in and turn on Prevent automatic sleeping on power adapter when the display is off in System Settings > Battery > Options; on a desktop Mac it is Prevent automatic sleeping when the display is off in System Settings > Energy. Pairing lives in the browser: another browser, a private window or cleared site data needs a new link, which only kaku remote on the Mac can make, so pair each device you plan to use before you leave.


Features (`docs/features.md`)

Features

Kaku Assistant

Kaku Assistant has two modes: automatic error recovery and on-demand command generation from natural language.

Setup

Run kaku ai to open the AI settings panel. Enable Kaku Assistant and edit the model, auth, base URL, and API key fields directly.

Field Description
Auth Type api_key (configure Kaku directly) or codex (follow your Codex connection)
Simple Model Used for # command generation, command fixes, and lightweight chat
Deep Model Used for primary Cmd + L / k chat and tool use
Base URL OpenAI-compatible API root, such as https://api.openai.com/v1
API Key Provider API key when Auth Type is api_key

For custom providers configured directly in Kaku, keep Auth Type set to api_key, enter the provider's OpenAI-compatible Base URL, and set the model names manually. With Auth Type set to codex, Kaku follows the user-level Codex connection under CODEX_HOME (falling back to ~/.codex), including API-key or ChatGPT login, the selected model provider, Base URL, query parameters, and provider headers. Project configs, named profiles, and CLI overrides are intentionally excluded. Unsupported authentication modes fail before Kaku sends a request.

Error recovery

When a command exits with a non-zero status, Kaku Assistant automatically sends the failed command, exit code, working directory, and git branch to the LLM and displays a suggested fix inline. Press Cmd + Shift + E to paste the suggestion into the terminal. Dangerous commands (e.g. rm -rf, git reset --hard) are pasted but never auto-executed.

The assistant does not trigger on: Ctrl+C exits, help flags, bare package manager calls, git pull conflicts, or non-shell foreground processes.

Natural language to command

Type # <description> at the prompt and press Enter to generate a shell command from plain English. Kaku intercepts the line before the shell sees it, sends your query along with the current directory and git branch to the LLM, and injects the resulting command back into the prompt ready to review and run.

text
# list all files modified in the last 7 days
# find and kill the process on port 3000
# compress the src folder excluding node_modules

The # prefix works in both zsh and fish. The original query stays visible while the request is in flight. If the model cannot produce a safe command, it injects a short explanation instead. Dangerous commands are loaded but flagged for review, never auto-executed.

assistant.toml fields

The config lives at ~/.config/kaku/assistant.toml:

Field Description
enabled true to enable, false to disable
api_key Your provider API key
model Simple Model for # command generation, command fixes, and lightweight chat; Follow Codex resolves the Codex model
chat_model Deep Model for primary Cmd + L / k chat and tool use; Follow Codex resolves the Codex model
chat_model_choices Optional curated list of chat models for the overlay picker
auto_fix_ignored_exit_codes Optional exit codes that should not trigger automatic command-fix suggestions, e.g. [2]
base_url OpenAI-compatible API root URL
api_mode chat_completions (default) or responses
native_web_search Add the provider-hosted web_search tool in Responses mode, with no separate search API key
custom_headers Extra HTTP headers for enterprise proxies, e.g. ["X-Customer-ID: your-id"]
web_search_provider Optional search backend: brave, pipellm, or tavily
web_search_api_key API key for the selected search backend
web_fetch_script Optional custom URL-to-Markdown fetch script
chat_tools_enabled Set to false to disable tool calling for chat providers without tool support
auth_type Advanced auth mode, e.g. api_key or codex
memory_curator_model Optional cheaper model for background memory curation

Older configs may still contain fast_model; Kaku treats it as the Simple Model and folds it back into model the next time the assistant settings are saved.

For a Responses-compatible endpoint, select responses under API Mode in kaku ai, or configure it directly:

toml
base_url = "https://api.openai.com/v1"
api_mode = "responses"
native_web_search = true

Kaku sends these requests to {base_url}/responses. Native web search runs at the model provider, so web_search_provider and web_search_api_key are not needed. Keep chat_completions for providers that only implement /chat/completions.

When auth_type = "codex", base_url, api_key, and api_mode do not define the connection. Kaku reads Codex's user configuration instead. New Codex-mode setups default both model fields to Follow Codex; either field can still be set to an explicit model as a Kaku-only override. The chat model switcher discovers available models from {Codex provider base_url}/models with that provider's resolved authentication, headers, and query parameters. Explicit Kaku model overrides are preserved when changing authentication modes. If the Codex config has no model, Kaku uses the first model returned by that endpoint.

AI Chat Panel

Press Cmd + L to open the built-in AI chat panel. It streams Markdown answers, highlights code blocks, can include terminal context, and can use approved tools for project files, shell commands, web search, and memory. Press Shift + Tab inside the panel to toggle between the Simple Model and Deep Model when they are different.

Use History, Context, and Model above the input to browse saved conversations, attach terminal context, and switch models. With an empty input, Tab focuses these controls and code actions, and Enter activates the focused action. Shift+Enter inserts a newline. During a reply, Esc or Stop cancels generation and keeps the partial answer; Enter with a draft interrupts and sends it. Scrolling up keeps your reading position while more text arrives; Latest returns to the response. Drafts survive switching conversations within the open panel.

Code blocks offer Copy without adding visual line wraps. Completed, single-line shell blocks also offer Insert, which pastes into the original shell without executing it. Tool permission requests open a scrollable review of the complete target and parameters. Enter allows, Esc denies, and the wheel or Page Up/Page Down scrolls the details.

From a shell, use k or kaku chat for the same conversation store:

bash
k "summarize the current project"
kaku chat

The standalone CLI is intentionally simpler than the overlay: it streams plain terminal text and supports /new, /resume, /clear, /status, /memory, and /exit.

Terminal Interactions

Cmd+Click opens URLs and file paths, and also bare domains such as github.com that have no scheme prefix. The matcher is tuned to leave code identifiers alone: method calls like df.info() and namespaces like System.Net never turn into links.

Option+Click moves the shell cursor within the current input line, including across soft-wrapped continuation rows. It never crosses a hard newline, so clicks into scrollback are ignored rather than mangling history.

Window Snapshots

Kaku saves multi-tab and multi-pane window layouts automatically when you close or hide a window. Use Shell > Restore Previous Window or Cmd + Option + Shift + T to reopen the last saved layout. Kaku tolerates missing or corrupted snapshot files and simply reports that no snapshot is available.

AppleScript

Kaku ships a minimal AppleScript dictionary so it shows up in Script Editor and other automation tools. The exposed surface is intentionally small and read-only apart from quit.

applescript
tell application "Kaku"
  get name        -- "Kaku"
  get version     -- e.g. "0.10.0"
  get frontmost   -- true / false
  quit            -- optional `saving ask|yes|no`
end tell

To browse the full dictionary, choose File > Open Dictionary in Script Editor and pick /Applications/Kaku.app. There is no do script verb, so AppleScript cannot run shell commands through Kaku.

Lazygit Integration

Press Cmd + Shift + G to launch lazygit in the current pane. Kaku auto-detects the lazygit binary from PATH or common Homebrew locations.

When a git repo has uncommitted changes and lazygit has not been used in that directory yet, Kaku shows a one-time hint to remind you it is available.

Install lazygit with brew install lazygit or via kaku init.

Yazi File Manager

Press Cmd + Shift + Y to launch yazi in the current pane. The shell wrapper y also launches yazi and syncs the shell working directory on exit.

Theme sync: Kaku automatically updates ~/.config/yazi/theme.toml to match the active color scheme (Kaku Dark or Kaku Light). No manual yazi theme setup needed.

Install yazi with brew install yazi or via kaku init.

Remote Files

Press Cmd + Shift + R to mount the current SSH session's remote filesystem locally via sshfs and open it in yazi.

Kaku auto-detects the SSH target from the active pane. The mount lives at ~/Library/Caches/dev.kaku/sshfs/<host>.

Requirements: sshfs installed (brew install --cask sshfs-mac) and passwordless SSH auth (key-based) for the remote host.

Remote Access

Run kaku remote to use this Mac's terminals from a desktop browser on another computer. It asks before turning remote access on, then prints a link that pairs one browser; bookmark the page after pairing to come back. The page has your tabs and splits, copy and paste, dropping files to upload them to the Mac, and Cmd+Click on a path to download it, and what you type and see is encrypted between the browser and Kaku. Remote access is off by default, and free: the relay is a server I pay for myself (FAQ). Commands are in the CLI reference.

Shell Suite

Kaku ships a curated set of shell plugins that load automatically inside Kaku sessions.

Zsh plugins (built-in)

  • z: Smarter cd that learns your most-used directories. Use z <dir>, z -l <dir> to list matches, z -t for recent directories.
  • zsh-completions: Extended completions for common CLI tools.
  • fast-syntax-highlighting: Live command coloring and error highlighting, with richer colors and faster startup than zsh-syntax-highlighting.
  • zsh-autosuggestions: Fish-style history-based completions as you type.

Fish support

Run kaku init to provision ~/.config/kaku/fish/kaku.fish for fish users. kaku doctor verifies both zsh and fish integration paths.

Optional tools (installed via kaku init)

  • Starship: Fast, customizable prompt with git and environment info.
  • Delta: Syntax-highlighting pager for git diff and grep.
  • Lazygit: Terminal git UI.
  • Yazi: Terminal file manager.

Smart Tab

Kaku's Smart Tab overrides the Tab key in zsh to provide smarter completion behavior. It supports three modes:

Mode Behavior Environment Variable
Completion First Tab shows the completion list; press Right Arrow to accept autosuggestions -
Suggestion First (default) Tab accepts autosuggestions when available, falls back to completion KAKU_TAB_ACCEPT_SUGGEST_FIRST=1
Off Disables Smart Tab entirely, restoring native zsh Tab behavior KAKU_SMART_TAB_DISABLE=1

You can also set the mode via kaku config (the Smart Tab option under Behavior) or in kaku.lua:

lua
config.smart_tab_mode = "suggestion_first"   -- default; Tab accepts autosuggestions first
config.smart_tab_mode = "completion_first"   -- Tab shows the completion list instead
config.smart_tab_mode = "off"                -- disable Smart Tab

If you prefer environment variables (for example, because you share your zshrc across terminals), add one of these before sourcing the Kaku shell integration:

zsh
export KAKU_TAB_ACCEPT_SUGGEST_FIRST=0  # completion-first (suggestion-first is the default)
# or
export KAKU_SMART_TAB_DISABLE=1         # disable Smart Tab

Environment variables set in your shell rc take precedence over kaku.lua settings. Smart Tab is zsh only and runs inside Kaku sessions (TERM_PROGRAM=Kaku, or tmux started from a Kaku shell).


Keybindings (`docs/keybindings.md`)

Keybindings

Opt = Option/Alt, Ctrl = Control.

Window

Action Shortcut
New window Cmd + N
Close pane / tab / hide Cmd + W
Hide application Cmd + H
Minimize window Cmd + M
Toggle fullscreen Cmd + Ctrl + F
Toggle always on top Cmd + Shift + Up
Quit Cmd + Q
Toggle global window Cmd + Opt + Ctrl + K

Cmd + W is smart: closes the active pane if there are multiple panes, closes the tab if there are multiple tabs or windows, otherwise hides the app.

Tabs

Action Shortcut
New tab Cmd + T
Switch to tab 1–8 / last tab Cmd + 1 – Cmd + 8 / Cmd + 9
Previous tab Cmd + Shift + [
Next tab Cmd + Shift + ]
Open Tab Navigator Cmd + Shift + O
Close tab Cmd + Shift + W
Reopen closed tab Cmd + Shift + T
Rename tab Cmd + Shift + I or double-click tab title

Turn on Tab Numbers in Settings (Cmd + ,) to show each tab's number, as in 1:dirname.

Panes

Action Shortcut
Split vertical Cmd + D
Split horizontal Cmd + Shift + D
Toggle split direction Cmd + Shift + S
Zoom / unzoom pane Cmd + Shift + Enter
Navigate panes Cmd + Opt + Arrows
Resize pane Cmd + Ctrl + Arrows

Shell Editing

Action Shortcut
Jump word left / right Opt + Left / Opt + Right
Jump to line start / end Cmd + Left / Cmd + Right
Delete to line start Cmd + Backspace
Delete word Opt + Backspace
Newline without execute Cmd + Enter or Shift + Enter

Font Size

Action Shortcut
Increase Cmd + =
Decrease Cmd + -
Reset Cmd + 0

Kaku Features

Action Shortcut
Clear screen + scrollback Cmd + K
Open Settings panel Cmd + , (type to filter model lists inside the panel)
Open Command Palette Cmd + Shift + P
Open AI settings Cmd + Shift + A
Open AI Chat Cmd + L
Apply Kaku Assistant suggestion Cmd + Shift + E
Restore previous window snapshot Cmd + Opt + Shift + T
Open lazygit Cmd + Shift + G
Open yazi file manager Cmd + Shift + Y
Browse remote files (SSH) Cmd + Shift + R
Open Doctor panel Ctrl + Shift + L

Mouse

Action Trigger
Copy selection to clipboard Release left mouse button after selecting
Open link Cmd + Click
Move cursor to clicked column Opt + Click (same row, shell prompt only)

The emoji and Nerd Font picker has no default shortcut. Open it from the Command Palette by searching emoji, or bind CharSelect as in the example below.

Custom Keybindings

Add bindings to ~/.config/kaku/kaku.lua by appending to config.keys. Do not assign a new table, this would erase Kaku's defaults.

lua
-- ~/.config/kaku/kaku.lua (after loading bundled config)
table.insert(config.keys, {
  key = 'RightArrow',
  mods = 'CMD|SHIFT',
  action = wezterm.action.ActivatePaneDirection('Right'),
})

-- Example: rebind AI Chat to Cmd+Shift+Space (original default):
table.insert(config.keys, {
  key = 'Space',
  mods = 'CMD|SHIFT',
  action = wezterm.action.EmitEvent('kaku-ai-chat'),
})

-- Example: open the emoji and Nerd Font picker with Cmd+Shift+U:
table.insert(config.keys, {
  key = 'u',
  mods = 'CMD|SHIFT',
  action = wezterm.action.CharSelect {},
})

-- Example: copy and paste with Ctrl+Shift+C / Ctrl+Shift+V as on Linux:
table.insert(config.keys, {
  key = 'c',
  mods = 'CTRL|SHIFT',
  action = wezterm.action.CopyTo('Clipboard'),
})
table.insert(config.keys, {
  key = 'v',
  mods = 'CTRL|SHIFT',
  action = wezterm.action.PasteFrom('Clipboard'),
})

For the full list of available actions, see WezTerm KeyAssignment reference.


Release Checklist (`docs/release-checklist.md`)

Release Checklist

macOS Tab Bar Matrix

Before shipping a release that touches windowing, titlebar coloring, tab bar
layout, or transparency, build the app with make app and verify these macOS
config combinations manually:

Tab position Tab style Opacity Window state Expected result
Top Fancy Opaque Windowed Tab text/icons stay visible below integrated traffic lights.
Top Fancy Transparent Windowed Tab text/icons stay visible; transparent titlebar has no gap.
Top Retro Opaque Windowed Tab text/icons stay visible below integrated traffic lights.
Top Retro Transparent Windowed Tab text/icons stay visible; transparent titlebar has no gap.
Bottom Fancy Opaque Windowed Bottom tab bar is visible and top content clears traffic lights.
Bottom Fancy Transparent Windowed Bottom tab bar is visible; top titlebar area has no gap.
Bottom Retro Opaque Windowed Bottom tab bar is visible and top content clears traffic lights.
Bottom Retro Transparent Windowed Bottom tab bar is visible; top titlebar area has no gap.
Top Fancy Opaque Fullscreen Native titlebar does not cover the rendered tab bar.
Bottom Fancy Opaque Fullscreen Bottom tab bar remains visible after entering and leaving fullscreen.

The key regression guard is update_titlebar_background() in
window/src/os/macos/window.rs: native titlebar coloring must remain opt-in for
opaque windows, otherwise NSTitlebarContainerView can cover the Metal-rendered
top tab bar.

Window Drag Regression Checks

After the backend drag-decision tests pass, check the built app on macOS:
single click must not restore a maximized window; dragging must restore and
move it; double-click must zoom according to the system preference. Repeat
across displays, with a manually screen-filling window, and in fullscreen.
The automated matrix covers disagreements between cached maximized state,
native zoom state, and screen-filling geometry; it does not prove AppKit's
interactive tracking behavior.

Repeatable Performance Checks

Use the same release build, display scale, window size, power mode, and machine
for before/after samples. Record the source revision and build profile. Debug
builds prove the harness works but are not release latency baselines.

Scenario Fixed workload Evidence
Startup RUNS=10 WARMUP=2 scripts/measure_startup_kaku.sh > startup.json Window and shell-ready mean, median and P95; cold resets only the fixture app cache.
Sustained output One 80x24 pane, 100,000 lines of 79 ASCII characters plus newline, repeated three times PTY byte rate, mux action latency, paint P95, peak RSS.
Multiple panes Four panes at the same total window size, each printing the same output workload Per-process CPU/RSS and paint P95; confirm input remains responsive in a fifth idle pane.
AI streaming A local OpenAI-compatible fixture emitting 20 fixed-size deltas/second for 30 seconds, repeated three times Paint P95 and CPU/RSS during streaming; cancel halfway once and confirm work stops. Network/provider latency is excluded.

Enable periodic_stat_logging = 5 in an isolated test config to collect existing
gui.paint.impl, read_from_pane_pty.bytes.rate, and
send_actions_to_mux.perform_actions.latency metrics. Use a fresh process per
scenario so percentile history does not mix workloads. The output workload is:

sh
python3 -c 'import sys; sys.stdout.write(("x" * 79 + "\n") * 100000); sys.stdout.flush()'

Run bash scripts/test_startup.sh after changing measurement or budget logic.
The schema 2 startup budget checks launch-to-shell-ready means; zeros disable
individual budgets until a release-build baseline exists. Preparation and
process cleanup run outside the timed interval. The cross-terminal comparison
script refuses to run while a target terminal is already open, and only
terminates processes it started.


--- METRICS ---