Profiles
On this page
A profile is a named, ordered group of extension manifests that kli installs as a unit at boot. It determines which extensions are present before any user extension loads: whether the terminal UI is built, which model providers are available, and which tools and commands exist. kli boots exactly one profile.
The kernel never learns about profiles. A profile installs through the same manifest primitives as any other extension group, and its activation record lives in per-protocol storage.
Built-in profiles
kli ships four built-in profiles. Each composes one or more of the manifest groups below and may declare seams (see Seams).
| Profile | Manifest groups | Declared seams | Terminal UI |
|---|---|---|---|
interactive-terminal | baseline, nix-declared, model-provider, tui-app | — | yes |
human-in-loop | baseline, nix-declared, model-provider, tui-app |
approval | yes |
autonomous | baseline, nix-declared, model-provider |
planner, scheduler, watchdog, recovery | no |
headless | baseline, nix-declared | — | no |
interactive-terminal is the default. A profile that omits the tui-app group
builds no TUI and runs no terminal loop; boot holds the main thread instead, and
boot diagnostics print to standard error rather than into a transcript.
interactive-terminal
The default profile. Installs the baseline, the model providers, and the terminal-UI extensions. This is the full interactive agent: a TUI with the transcript, input editor, status widgets, completion, slash commands, and the session bound for chat on boot. Declares no seam.
human-in-loop
The same manifest groups as interactive-terminal — baseline, model providers,
and the terminal UI — and additionally declares the approval seam. The
approval seam is declared, not implemented: the profile names the extension
point but supplies nothing for it, and kli ships no approval provider. Booting
human-in-loop today gives you the same running extensions as
interactive-terminal. The seam marks where an approval extension would attach.
autonomous
Installs the baseline and the model providers, and omits the tui-app group, so
it builds no terminal UI. Declares four seams: planner, scheduler,
watchdog, and recovery. As with approval, these are declared extension
points, not implemented behavior; kli ships no provider for any of them. Booting
autonomous brings up the agent substrate without a TUI and holds the main
thread.
headless
The baseline group only: no model providers and no terminal UI. The minimal substrate. Provider and UI extensions are absent, so the session is not bound for chat on boot. The agent substrate stays alive without a terminal loop.
Manifest groups
The groups each built-in profile composes from.
| Group | Contents |
|---|---|
| baseline |
The kernel-facing substrate present in every profile: object and event extensions, the command and config services, the session log, the context lens, auth and OAuth, the model registry and runtime, the agent loop and session, the eval, bash, read, write, edit, find, and search tools, the filesystem-anchor lifecycle, and the runtime control, journal, snapshot, history, and introspection extensions. |
| nix-declared | Extensions a Nix-configured image declares present at boot. Empty in plain kli; only a configured image's boot shim populates it. Each profile splices it in directly after the baseline, so declared extensions boot as baseline children. |
| model-provider |
The four model providers: openai-codex, openai, anthropic, and compatible. See Providers. |
| tui-app |
The terminal UI and everything bound to it: style, keymap, status, views, input, editor, terminal, markdown, transcript, and the TUI app itself; the basic and session commands; the eval, bash, and model commands; config commands; prompt templates; context-file commands; skills; completion; settings wiring; and observability. |
Seams
A seam is a capability a profile declares as an extension point but does not provide itself. It names where a user (or a future extension) is expected to attach a provider to complete the profile. A profile carries its declared seams in its activation record; declaring a seam installs nothing and runs nothing.
No built-in seam has an implementation in kli today. The approval seam declared
by human-in-loop and the planner, scheduler, watchdog, and recovery
seams declared by autonomous are markers only. In particular, human-in-loop
does not gate tool execution behind an approval step: kli is
fully permissioned by default, and no profile
changes that.
Selection precedence
kli resolves the boot profile name from the first source that supplies one, in this order:
- The
--profile <name>command-line flag. - The
KLI_PROFILEenvironment variable, when set and non-empty. - The
profilekey in settings (a non-empty string). The merged settings put the project file over the global file, so a project.kli/settings.jsonvalue overrides the one in~/.config/kli/settings.json. - The default,
interactive-terminal.
A name that resolves to neither a built-in profile nor a declared data profile
warns and falls back to interactive-terminal. The warning surfaces as a boot
diagnostic.
The name is matched case- and separator-insensitively (normalized to a keyword),
so human-in-loop and HUMAN_IN_LOOP name the same profile.
Custom data profiles
A data profile is a profile declared as data in settings rather than as a
built-in. It lives under a profiles object in settings.json, keyed by
profile name:
{
"profiles": {
"review": {
"extends": "interactive-terminal",
"enable": ["my-review-helper"],
"disable": ["some-noisy-extension"],
"settings": {
"model": "anthropic/claude-..."
}
}
}
}
Each entry accepts these fields. All are optional.
| Field | Type | Effect |
|---|---|---|
extends | string |
Name of the profile this one builds on: another data profile or a built-in. The extends chain is walked until it bottoms at a built-in, which supplies the manifest groups. An entry with no extends bottoms at interactive-terminal. |
enable | array of strings | User-extension ids to add to the effective set. A later entry in the chain has the last word over an earlier one for a given id. |
disable | array of strings |
User-extension ids to remove from the effective set. enable and disable for the same id resolve to whichever the chain states last. |
settings | object |
A settings overlay recorded for this profile. It merges over the chain's earlier overlays and is applied as the topmost settings layer (global < project < overlay) when the profile is active. |
A data profile is resolved into a base built-in plus effective enable and
disable delta sets and a merged settings overlay. The base built-in's manifest
groups install at boot; the deltas then gate which user extensions load on top.
Data profiles change the user-extension set and settings, not the built-in
manifest groups: a data profile cannot add a manifest group its base does not
already include.
Resolution is fail-soft. A malformed entry warns and is skipped. An entry whose
name collides with a built-in profile warns and is skipped — built-in names
cannot be shadowed. An unknown extends target or a cyclic extends chain warns
and the profile fails to resolve. Each warning surfaces as a boot diagnostic.
Live switching
While kli is running, /profile with no argument lists the available profiles
with the active one marked, and /profile <name> switches to a named profile by
re-basing the user-extension pool onto the target's effective set and swapping
its settings overlay. A switch that would change the built-in base does not take
effect live; the base applies only at boot, and kli tells you to restart with
--profile <name>. See the CLI reference for boot-time selection.