Get from install to your first autonomous coding task in a couple of minutes.
brew tap mlhher/late && brew install latecurl -sfL https://raw.githubusercontent.com/mlhher/late-cli/main/install.sh | bashManual binaries for Linux, macOS, and native Windows are available from the GitHub Releases.
Late automatically looks for an OpenAI-compatible llama-server on localhost:9931.
Start llama-server with your GGUF model as usual, then launch Late from your project:
cd your-project
lateThat's it. If llama-server is already running on :9931 (its default port) Late will connect with no configuration required.
Late works with any OpenAI-compatible APIs including DeepSeek, Claude, GPT, Kimi, GLM, OpenRouter, and others.
Set:
# DeepSeek
export OPENAI_BASE_URL="https://api.deepseek.com" # your-api-url
export OPENAI_API_KEY="sk-123" # your-api-key
export OPENAI_MODEL="deepseek-flash" # your-model-nameThen run:
cd your-project
lateYou can later persist model settings in Late's config.json instead of exporting environment variables every time.
Persistent configuration lives at:
- Linux:
~/.config/late/config.json - macOS:
~/Library/Application Support/late/config.json - Windows:
%APPDATA%\late\config.json
Configuration precedence is:
- Environment variables
config.json- Late defaults
For the standard local llama-server setup on localhost:9931, you do not need to create a configuration file.
You can choose how much supervision Late applies to dangerous commands by adding a permission-mode entry to the config.json file for your platform (see the locations above):
{
"permission-mode": "ask-for-user-approval"
}The two allowed values are:
ask-for-user-approval— the default. Potentially dangerous commands require your approval.i-promise-i-have-backups-and-will-not-file-issues— run every tool without user confirmation.
Notes:
- The two CLI flags of the same names (
--ask-for-user-approval,--i-promise-i-have-backups-and-will-not-file-issues) are mutually exclusive and override theconfig.jsonvalue. - Omitting the entry (and any flag) defaults to
ask-for-user-approval. - An invalid value is ignored with a warning and the safe default applies.
By default, Late uses the same model for the orchestrator and its subagents. However, you can map different models to specific agent roles (e.g., using a massive frontier model for planning, and a faster local model for execution).
You can change models interactively using /model inside the TUI, or persist your hybrid routing in config.json via the models registry:
{
"models": [
{
"id": "deepseek",
"url": "https://api.deepseek.com",
"key": "sk-your-key",
"model": "deepseek-flash"
},
{
"id": "local-qwen",
"url": "http://localhost:9931",
"key": "",
"model": "qwen3.6-35b-a3b"
},
{
"id": "local-gemma",
"url": "http://localhost:9931",
"key": "",
"model": "gemma-4-e4b"
}
],
"agent_models": {
"orchestrator": "deepseek",
"researcher": "local-qwen",
"coder": "local-gemma"
}
}Note: For backward compatibility, the older flat format using
openai_base_url,late_subagent_model, etc., is also still supported.
Late keeps the orchestrator and active subagents visible inside the same terminal interface.
The essentials:
| Key / Command | Action |
|---|---|
Tab |
Switch between the orchestrator and active subagents |
Ctrl+O |
Attach a file |
Ctrl+R / click |
Expand or collapse tool output (all / one call) |
Esc / Ctrl+G |
Stop the currently running agent |
/model |
Change orchestrator or worker models |
/rewind |
Rewind to an earlier point in the conversation |
/themes |
Change the TUI theme |
/compose |
Draft a longer instruction in your $EDITOR |
Ctrl+D / Ctrl+C |
Quit |
Type / at any time to open the command picker (Tab fills in the highlighted command so you can add arguments, Enter runs it), and @ anywhere in your prompt to pick a project file by name (fuzzy, Tab/Enter to insert; files ignored by .gitignore/.llmignore are not offered).
When Late creates subagents, each appears in its own tab while it works and disappears after completing its task.
Every finished tool call shows its outcome on the same row: ✓ +3 -1 for an edit, ✗ exit 1 · FAIL for a failing command, ⊘ denied for a call you refused. Click a row (or press Ctrl+R for all of them) to see the detail behind it: the diff of an edit, the output of a command, or a subagent's full report. Subagent tabs close when the subagent finishes, but its report stays reachable this way in the orchestrator's transcript.
/timestampstoggles quietHH:MM:SStimestamps on transcript messages (bottom-right of your prompt card, right-aligned under each reply).- The toggle persists to
config.json(show-timestamps).
- A single-line info row sits under the status bar (shown by default;
/infobartoggles it). Left to right: the focused agent's endpoint host and model (localhost:9931 · qwen3.5-4b), the approval mode (approval ask, orapproval offwhen running unsupervised), todo progress (todos 3/7), and the subagents that are running or waiting for your approval (shown only while there are any). - On the right,
turn 1m42stimes the current turn: it starts when you send a message, runs while any agent is working, and freezes when they are all idle, so it keeps showing how long the last turn took until you send the next message. - On a narrow terminal whole segments are dropped (the host first, then turn time, todos, subagents, approval) rather than cut in half; very long hosts and model names are clipped with an ellipsis.
- The toggle persists to
config.json(show-info-bar).
- The todos pane shows the orchestrator's todo list on the right side of the transcript. It stays closed until the first todos are created and then opens by itself, once; the transcript narrows to make room.
/todostoggles it at any time, and once you have toggled it yourself it never moves on its own. - Set
"show-todo-pane": trueinconfig.jsonto start with it open, orfalseto keep it closed and never open it by itself. - Terminals narrower than 85 columns keep it closed; if you widen the window later, a pane still waiting to open does so.
- Click inside the pane (or press
Ctrl+T) to focus it for scrolling; a focused pane is highlighted and marked[focused · esc to unfocus].Escor a click anywhere outside releases focus, and so does the first printable key you type, which still lands in the input, so the pane never swallows your typing.
Potentially destructive commands and file changes require approval unless you have already granted permission for that scope.
When prompted, you can approve:
- once;
- for the current session;
- for the current project;
- globally.
The prompt shows what is about to happen: the command and its working directory for shell commands, and a line-by-line diff (with line numbers) for file edits and writes. It also lists exactly what s, p and g would trust beyond this one call, for example go test (flags: -race).
To deny, press n. To deny and tell the agent why, type your reply and press Enter: the agent receives it together with the denial and can change course instead of guessing.
Read-only operations are generally handled automatically.
Approvals decay over time rather than becoming permanent trust forever.
For unattended work, large refactors, or overnight runs, use late-podman.
It runs Late inside an isolated rootless Podman container rather than giving the agent unrestricted access to your host.
From inside your project run:
late-podmanLate automatically looks for container configuration in the project, including .devcontainer/devcontainer.json. For an example check Late's own devcontainer.json.
You can also specify an image explicitly:
late-podman --image your-development-imageArguments after -- are forwarded to Late:
late-podman -- --continueYour current workspace is mounted read-write at /workspace. Late keeps its own session and cache volumes, forwards your SSH agent when available, and mounts your Late configuration read-only if present. Your host home directory and container socket are not exposed by default.
Note:
late-podmanrequires Linux with Podman installed. Includes additional SELinux support. Works out of the box with Silverblue and Universal Blue images.
Note: Devcontainer configurations may declare additional mounts. Late respects those when constructing the sandbox.
For scripts or unattended workflows:
late --prompt "Run the test suite, diagnose the failures, and fix them."If using late-podman:
late-podman -- --prompt "Refactor this package and verify all tests."Late automatically saves sessions.
Resume the most recently updated session, no matter which project it belongs to:
late --continueResume the most recently updated session for the current project. The project is resolved as the git repository root containing your working directory (falling back to the working directory itself outside a repository), so this also works from inside a subdirectory:
late --continue-projectThe two flags are mutually exclusive: pass at most one. Sessions from other projects — or ones created before the project directory was recorded — can be found with late session list (use -v to see each session's project folder) and resumed with late session load <id>:
late session list -v
late session load <id>Late supports the Model Context Protocol (MCP) to let you bring your own external tools. Add your MCP servers to one of the following locations:
- Linux:
~/.config/late/mcp_config.json - macOS:
~/Library/Application Support/late/mcp_config.json - Windows:
%APPDATA%\late\mcp_config.json - Project-local:
.late/mcp_config.json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "my-mcp-server"]
}
}
}Skills are reusable sets of markdown instructions. They are discovered automatically from:
- Linux:
~/.config/late/skills/ - macOS:
~/Library/Application Support/late/skills/ - Windows:
%APPDATA%\late\skills\ - Project-local:
.late/skills/
No setup required. Just drop your skills into the respective folders, and Late will automatically load them.
Plugins bundle skills, slash commands, MCP servers, hooks, themes, and inline tools into one installable unit.
You can find the default registry at https://github.com/mlhher/late-plugins.
# Install from the default registry or npm fallback
late plugin install notify-tool-approval
# Install from a Git repo
late plugin install https://github.com/you/late-plugin.git
# Install from a local path for development
late plugin install ./my-pluginFor plugin development and manifest formatting, see the Plugin SDK.
Late's native search tool respects your project's .gitignore automatically, saving LLM context by excluding vendor and build directories.
You can also create an .llmignore file alongside your .gitignore to specifically hide files from the agent (e.g., secrets, large binaries, test fixtures, or generated code) without affecting your git tracking.
Transient LLM API failures are retried automatically, so a flaky gateway rarely interrupts a run:
- Transport errors — connection refused/reset, timeouts, and mid-stream disconnects (the server accepted the request, then the body died) — are retried.
- HTTP 408, 429, and 5xx responses are retried; HTTP 400 gets a few quick retries.
- Each retry waits a jittered exponential backoff (500 ms base, capped at 30 s). A server
Retry-Afterheader is honored as a floor, capped at 5 minutes. - Failures that retrying cannot fix fail fast: TLS/certificate errors, unsupported URL schemes, and plain HTTP on an HTTPS endpoint.
The retry budget is resolved as CLI flag > environment variable > built-in default:
--max-stream-retries <n>— maximum retries per stream call (default: 10)LATE_MAX_STREAM_RETRIES— environment variable, used when the flag is not passed
Setting 0 (or a negative value) disables stream retrying entirely. Run late -h to see all flags.
Small or poorly-sampled models sometimes get stuck issuing the same tool call forever. Late watches each turn's tool calls and their results:
- If the last N turns are identical (same calls, same output), or alternate between two identical turns (A, B, A, B, …), Late injects a one-time warning telling the model to change approach or ask you.
- If the model keeps repeating after the warning, the run stops with an error saying the model kept repeating the same tool calls. Your session is intact; send a new message to continue.
- Any change in a call or its output counts as progress and resets the detector, so re-running a build after an edit is never flagged.
The threshold N is resolved as CLI flag > environment variable > built-in default:
--loop-threshold <n>— identical turns in a row before warning (default: 5)LATE_LOOP_THRESHOLD— environment variable, used when the flag is not passed
Setting 0 (or a negative value) disables loop detection.
If your local model loops often, check the server settings first, since they are the usual cause:
- Temperature too low. Very low values (e.g. 0.1) make loops likely, especially on MoE models. Use the model's recommended sampling (e.g. Qwen: temp 0.6–1.0, top-p 0.95, top-k 20).
- Context shifting / "Truncate Middle". Silently dropping context confuses the model. Prefer "stop at limit" and a larger context.
- No KV-cache quantization. Q8 (or Q4) KV cache lets you fit a much larger context in the same VRAM.
For non-coding use (specifically with a custom system prompt), you may also want to look at Minh Nhat Nguyen et al., ICLR 2025: Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs for guidance on sampling settings.
| Flag | Description |
|---|---|
--help |
Show all flags and commands |
--version |
Show version information |
--continue |
Resume the latest session, regardless of project directory |
--continue-project |
Resume the latest session in the current project (git repo root of the working directory; falls back to the working directory outside a repo) |
--prompt "..." |
Start the agent immediately with the given prompt |
--suppress-thinking-words |
Apply a default Logit bias map of overthinking words (llama.cpp only) |
--logit-bias and --subagent-logit-bias |
Manually set the logit biases for specific models (llama.cpp only) |
--gemma-thinking |
Inject thinking tokens for Gemma 4 models |
--subagent-max-turns <n> |
Set max turns per subagent (default: 500) |
--append-system-prompt "..." |
Append text to the system prompt (e.g. further instructions) |
--enable-images |
Treat models as supporting images (for non llama.cpp servers) |
--save-subagent-histories |
Persist subagent conversation histories to disk |
--max-async-subagents <n> |
Max subagents running at the same time (default: 1). Env: LATE_MAX_ASYNC_SUBAGENTS |
--max-stream-retries <n> |
Max retries per LLM stream call with jittered exponential backoff (default: 10); 0 disables stream retrying. Env: LATE_MAX_STREAM_RETRIES |
--loop-threshold <n> |
Warn, then stop, after this many identical tool-call turns in a row (default: 5); 0 disables. Env: LATE_LOOP_THRESHOLD |
--ask-for-user-approval |
Require user approval for dangerous commands (default; overrides config.json permission-mode) |
--i-promise-i-have-backups-and-will-not-file-issues |
Run every tool without user confirmation (overrides config.json permission-mode) |
The two permission flags above are mutually exclusive: pass at most one of --ask-for-user-approval or --i-promise-i-have-backups-and-will-not-file-issues.