lucinate — the terminal-native AI chat client
Chat with your OpenClaw agents, a Hermes profile, or any OpenAI-compatible endpoint (Ollama, vLLM, LM Studio, OpenAI proper) — from the terminal. Streaming responses, markdown rendering, no mouse required.
No file browsers, no task boards, no dashboards. Just chat.
### Highlights
- **Multiple backends** — connect to an [OpenClaw](https://github.com/openclaw/openclaw) gateway, a [Hermes Agent](https://github.com/nousresearch/hermes-agent) profile, or any OpenAI-compatible endpoint ([Ollama](https://ollama.com), vLLM, LM Studio, llamafile, OpenAI proper). Switch between saved connections with `/connections`.
- **Streaming responses, conversation history, and multi-agent support**
- **Create and delete agents** directly from the TUI — gateway-managed for OpenClaw, or local `IDENTITY.md` + `SOUL.md` markdown for OpenAI-compatible backends. Delete is type-the-name to confirm, with an optional "keep files" toggle so you can drop the listing without nuking the content. Hermes profiles are configured server-side via `hermes profile create`
- **Markdown rendering** for assistant messages
- **Tool call cards** — when the agent invokes a tool, an inline card shows what's running, what arguments it got, and whether it succeeded or failed (OpenClaw)
- **Shell commands** — run locally with `!` or remotely on the gateway with `!!`
- **Message queueing** so you can keep typing while the agent is responding
- **Scroll and copy like a native** — the wheel scrolls history, click-drag selects and copies on release, and `↑`/`↓` recall what you typed. All three, no fighting.
- **Local agent skills** loaded from `~/.agents/skills/` — invoke as a slash command (`/review`) or drop one mid-message (`use /review on the diff`)
- **Routines** — author multi-step prompt sequences once, replay them with `/routine `. Auto-advance after each reply, or step through manually. Manage them in-TUI with `/routines`.
- **Live token/cost stats** in the header bar (OpenClaw)
- **Thinking level control** via `/think` — tune reasoning depth per session (OpenClaw)
- **Cron browser** — list, edit, run, create, and duplicate scheduled jobs without leaving the terminal (OpenClaw)
- **Per-agent header colour** — set the chat header background to any hex colour with `/header ` and the override sticks to that agent, persisted across runs
## Install
With [Homebrew](https://brew.sh) (macOS / Linux):
```sh
brew trust --formula lucinate-ai/tap/lucinate
brew install lucinate-ai/tap/lucinate
```
Or via the install script (macOS / Linux):
```sh
curl -fsSL https://raw.githubusercontent.com/lucinate-ai/lucinate/main/install/lucinate.sh | sh
```
On Windows, in PowerShell:
```powershell
irm https://raw.githubusercontent.com/lucinate-ai/lucinate/main/install/lucinate.ps1 | iex
```
Or, if you have Go 1.25+:
```sh
go install github.com/lucinate-ai/lucinate@latest
```
Or build from source:
```sh
git clone https://github.com/lucinate-ai/lucinate.git
cd lucinate
go build -o lucinate .
```
## Getting started
### 1. Configure lucinate
On first launch lucinate opens a **Connections** picker so you can add a backend.
Three connection types are supported:
- **[OpenClaw](docs/backend_openclaw.md)** — connect to an OpenClaw gateway over WebSocket. Auth uses Ed25519 device pairing.
- **[OpenAI-compatible](docs/backend_openai.md)** — Ollama, vLLM, LM Studio, llamafile, OpenAI - connect to any `/v1/chat/completions` endpoint.
- **[Hermes (Nous Research)](docs/backend_hermes.md)** — connect to a Hermes Agent profile's `/v1/responses` API server. One Lucinate connection maps to one Hermes profile; chat state lives server-side.
OpenClaw URLs can use `https`, `http`, `wss`, or `ws` — lucinate derives the WebSocket endpoint automatically. OpenAI-compatible and Hermes URLs are HTTP(S) base URLs ending in `/v1`.
Switch between saved connections at any time with `/connections` from the chat view. Use `n` to add a new one, `e` to edit, `d` to delete (with confirmation).
### 2. Connect
```sh
lucinate
```
#### First-time pairing (OpenClaw only)
On first run, lucinate generates an Ed25519 device identity under `~/.lucinate/identity//` (keyed by gateway host) and sends a pairing request to the gateway. The TUI shows a "pairing required" prompt with the next steps. On the gateway host, run:
```sh
openclaw device list --pending
```
You should see lucinate's device ID. Approve it:
```sh
openclaw device approve
```
Press Enter in the lucinate prompt to retry — the connection completes in place, the gateway issues a device token, and you land in the agent picker. No restart needed.
### 3. Pick an agent
Select an agent from the list to start chatting.
| Key | Action |
|-----|--------|
| `Enter` | Select agent |
| `n` | Create a new agent |
| `d` | Delete the highlighted agent (type-to-confirm) |
| `Ctrl+C` | Quit |
### 4. Chat
| Key | Action |
|-----|--------|
| `Enter` | Send message |
| `Alt+Enter` | Insert newline |
| `Ctrl+W` | Delete word |
| `↑` / `↓` | Recall previously sent messages (bash-style) |
| `PgUp` / `PgDn` | Scroll chat history |
| `Tab` | Show slash-command menu, extend to common prefix, then cycle |
| `Shift+Tab` | Cycle backward through matches |
| `Esc` | Back to agent list |
| `Ctrl+C` | Quit |
The mouse works too: **wheel scrolls the history**, and **click-drag selects
text** — it lands on your clipboard the moment you let go. Prefer your
terminal's native selection? `/mouse off` hands the mouse back.
### Settings
Use `/settings` to open the settings view (also reachable as `/config`). Your settings are persisted to `~/.lucinate/config.json`.
| Setting | Default | Description |
|---------|---------|-------------|
| Completion notification | On | Ring the terminal bell when a response completes (only if the terminal isn't focused) |
| Check for updates on startup | On | Once a day, fetch a tiny manifest from `lucinate.ai` and show a subtle `↑` badge in the chat header when a newer release is out. No telemetry — just a single GET. |
| History limit | 50 | Number of messages loaded when restoring a session (range 10–500) |
| Connect timeout | 15s | Per-attempt deadline for the initial connect and each reconnect (range 5–300s — bump it for slow local LLMs) |
| Ask command defaults | — | Connection, agent, session, and detach values pre-filled for `lucinate ask`. Opens a sub-screen (`Enter`); leave a field blank to keep requiring it on the command line. |
In the settings view, use `Space` to toggle checkboxes, `←`/`→` to adjust numeric values, and `Enter` to open a sub-screen like **Ask command defaults**. The settings screen is also reachable from the connections and agent lists with `s`.
## Commands
Type these in the chat input. As soon as you type `/`, a menu shows every matching command and skill. Tab extends the input to the longest common prefix; press it again at the prefix to cycle through candidates (Shift+Tab to cycle back). The same menu and Tab cycling apply to agent names after `/agent `.
| Command | Action |
|---------|--------|
| `/help` | Show available commands |
| `/agents` | Return to agent picker |
| `/agent ` | Switch to a named agent (fuzzy match) |
| `/cancel` | Cancel the in-progress response (also: `Esc`) |
| `/clear` | Clear chat display |
| `/compact` | Compact session context — server-side on OpenClaw, local summarisation pass on OpenAI-compatible backends (with confirmation) |
| `/settings` | Open settings (also `/config`) |
| `/connections` | Switch backend connection |
| `/crons` | List and manage gateway cron jobs (default: filter by current agent; `/crons all` shows global) — OpenClaw only |
| `/cron ` | Run a named cron job now, after a y/n confirmation — OpenClaw only |
| `/header ` | Set the chat header background for the current agent to a hex colour (e.g. `#4FC3F7`); the override sticks to that agent and persists across runs. Bare `/header` reports the current agent's value, `/header reset` restores the default. |
| `/models` | Open the model picker (filter as you type) |
| `/model ` | Switch model (fuzzy match) |
| `/mouse on\|off` | Mouse capture (on by default: wheel scrolls, drag copies; off: your terminal's native selection) |
| `/reset` | Delete session and start fresh (with confirmation) |
| `/routine ` | Activate a stored multi-step routine in the current session |
| `/routines` | List, view, edit, or delete routines |
| `/sessions` | Browse and restore previous sessions |
| `/skills` | List available agent skills |
| `/stats` | Show token usage and cost breakdown — OpenClaw only |
| `/status` | Show backend, endpoint, auth, versions, and local session stats |
| `/think` | Show current thinking level — OpenClaw only |
| `/think ` | Set thinking level (`off`, `minimal`, `low`, `medium`, `high`) — OpenClaw only |
| `/quit`, `/exit` | Quit lucinate |
## Shell commands
### Local commands
Prefix input with `!` to run a command locally on your machine. The input border turns green to indicate local execution mode.
```
!ls -la
!git status
!cat README.md
```
### Remote commands
Prefix input with `!!` to run a command on the gateway host. The input border turns amber to indicate remote execution mode.
```
!!hostname
!!ls -la /tmp
!!uptime
```
The gateway's exec security policy controls which remote commands are allowed. If a command is denied, you'll see an error message. Configure exec permissions on the gateway host using `openclaw config`.
## Routines
Recurring prompt workflow you find yourself retyping every Tuesday? Save it as a routine. Each routine is an ordered list of steps; each step is a complete user message. Activate one with `/routine ` and lucinate fires the steps at the assistant in order, optionally auto-advancing after every reply.
Manage them with `/routines` — list, view, add, edit, delete. The form has one textarea per step plus `Alt+↑` / `Alt+↓` to insert above/below and `Alt+Delete` to remove. `Ctrl+S` saves.
Routine files live at `~/.lucinate/routines//STEPS.md`. The format is plain markdown with optional YAML frontmatter and `---` between steps:
```markdown
---
name: review-pr
mode: auto
log: ./review.log
---
list the files changed in the current PR
---
flag any obvious bugs or style issues, one per line
---
write a one-paragraph review summary
```
`mode: auto` advances on every assistant reply; `manual` (the default) waits for `Enter`. `log:` is optional — when set, each turn is appended to that file, prefixed `user: ...` / `assistant: ...` with ISO timestamps.
While a routine is running you'll see a status row above the input:
```
routine: review-pr — AUTO — sent: 2/3 — next: write a one-paragraph review summary
```
Useful keys mid-routine:
| Key | Action |
|-----|--------|
| `Shift+Tab` | Cycle the mode (auto ↔ manual) |
| `Enter` (empty input) | Send the next step (manual / paused mode) |
| `Esc` | Cancel the routine and any in-flight reply |
The assistant can steer the routine in its own reply by emitting one of these on its own line:
| Directive | Effect |
|-----------|--------|
| `/routine:stop` | End the routine immediately |
| `/routine:pause` | Pause until you press `Enter` |
| `/routine:continue` | Explicit no-op (also resumes a paused auto-mode routine) |
| `/routine:mode auto` | Switch to auto mode |
| `/routine:mode manual` | Switch to manual mode |
Routines live entirely client-side and work with every backend.
## One-shot mode
Not every prompt needs a TUI. `lucinate send` dispatches a single message through one of your saved connections, waits for the assistant's first complete reply, and prints it to stdout — nothing else. No streaming, no spinner, no chrome. Safe to capture into a shell variable, pipe into `jq`, or schedule from cron.
```sh
lucinate send --connection my-con --agent main "summarise this PR description"
```
| Flag | Description |
|------|-------------|
| `--connection`, `-c` | Saved connection name or ID (case-insensitive on name). Required. |
| `--agent`, `-a` | Agent name or ID within the connection (case-insensitive on name). Required. |
| `--session`, `-s` | Session key. Defaults to the agent's main session — same default the picker would pick. |
| `--detach`, `-d` | Dispatch the message and exit as soon as the gateway accepts the turn. No reply is awaited. |
The reply is written to stdout with a single trailing newline. Errors go to stderr; the exit code is non-zero on failure. Messages that begin with a dash should be preceded by `--` (the standard Unix escape) so the flag parser leaves them alone.
A couple of patterns this enables:
```sh
# capture a reply into a shell variable (short flags work too)
reply=$(lucinate send -c my-con -a main "what's the changelog entry for this commit?")
echo "$reply" | tee notes.md
# fire-and-forget from cron — the run continues server-side, the next TUI session sees the reply
lucinate send --connection my-con --agent main --detach "kick off the morning digest"
```
### Ask: send with your defaults baked in
Typing `-c my-con -a main` on every call gets old. `lucinate ask` is `send` with the connection, agent, session, and detach flags pre-filled from a saved profile, so day to day it's just:
```sh
lucinate ask "what's on my plate today?"
```
Set the defaults once in the TUI under `/settings` → **Ask command defaults**. Any flag you pass still wins — `lucinate ask -a other "…"` overrides the saved agent for that one call — and leaving a field blank in the settings screen keeps requiring it on the command line.
For the lifecycle, the default-session rule, embedding `app.Send` from Go, the detach contract, and the `ask` alias, see [docs/one-shot.md](docs/one-shot.md).
## Skip the pickers
Already know which connection, agent, and session you want? `lucinate chat` drops you straight in — same TUI as the bare invocation, just pre-navigated past the pickers. Hand it a message and it's your first turn, auto-submitted once history loads.
```sh
lucinate chat --connection my-con --agent main "kick things off"
```
| Flag | Description |
|------|-------------|
| `--connection`, `-c` | Saved connection name or ID (case-insensitive on name). Optional — defaults to the same auto-pick the bare `lucinate` uses. |
| `--agent`, `-a` | Agent name or ID to auto-select. A miss surfaces as an error on the picker rather than silently picking the wrong one. |
| `--session`, `-s` | Session key to open. Defaults to the agent's main session — same default the picker would pick. |
Every flag is optional. `lucinate chat` with no flags and no message is functionally identical to bare `lucinate`. Messages that begin with a dash should be preceded by `--`, same Unix escape as `send`.
Unlike `send`, this stays in the TUI — the auto-submitted message is just your opening turn, not a one-shot exit. For the override-plumbing internals, see [docs/chat-launch.md](docs/chat-launch.md).
### Command line flags
| Flag | Description |
|------|-------------|
| `--help`, `-h` | Show top-level usage and exit. `lucinate help ` prints command-specific usage. |
| `--version`, `-v` | Print version and exit |
### Environment variables
Prefer env vars? Either is recognised on first run and auto-added as a connection:
```sh
OPENCLAW_GATEWAY_URL=https://your-gateway-host
LUCINATE_OPENAI_BASE_URL=http://localhost:11434/v1
LUCINATE_OPENAI_API_KEY=sk-... # optional
LUCINATE_OPENAI_DEFAULT_MODEL=llama3.2 # optional
```
Other knobs:
```sh
LUCINATE_DISABLE_UPDATE_CHECK=1 # opt out of the daily update check, regardless of the toggle in /settings
LUCINATE_LOG_LEVEL=warn # debug | info | warn (default) | error
LUCINATE_LOG_FILE=/path/to/lucinate.log # path to log file. TUI defaults to /lucinate-events.log; non-TUI subcommands default to stderr
LUCINATE_LOG_FORMAT=text # text (default) | json
```
The TUI never writes diagnostics to your terminal — they would corrupt the rendered frame — so by default log output goes to a side file in the OS temp dir (`lucinate-events.log`). Bump `LUCINATE_LOG_LEVEL=debug` and tail it when something looks off. See [docs/logging.md](docs/logging.md) for the full design.
## Built on
lucinate uses the [openclaw-go](https://github.com/a3tai/openclaw-go) SDK for gateway communication. The TUI is built with [Bubble Tea](https://github.com/charmbracelet/bubbletea), [Bubbles](https://github.com/charmbracelet/bubbles), and [Lip Gloss](https://github.com/charmbracelet/lipgloss), with markdown rendered via [Glamour](https://github.com/charmbracelet/glamour).
Device identity (Ed25519 keypair and device token) is stored at `~/.lucinate/identity//`, isolated per gateway endpoint.
## License
Apache 2.0
---
OpenClaw is a trademark of its respective owner(s), including Peter Steinberger. This site is not affiliated with, endorsed by, or sponsored by OpenClaw or its contributors.