#ai-agent #tui #llm

bin+lib lucid-train

Lucid Train: an agentic terminal coding harness with a streaming TUI. OpenRouter, self-hosted, and local open-source models.

10 releases

new 0.1.135 Jul 10, 2026
0.1.134 Jul 8, 2026
0.1.131 Jun 29, 2026

#424 in Development tools

MIT license

640KB
13K SLoC

>_ Lucid Train

An agentic terminal harness with a Codex-style TUI, written in Rust.

Lucid Train ports the evolved-harness design from Agentic Harness Engineering (a top Terminal-Bench ranker) into a fast, single-binary CLI with a UI modeled on OpenAI Codex.

╭────────────────────────────────────────────╮
│ >_ Lucid Train (v0.1.0)                    │
│                                            │
│ model:     kimi-k2.5   /model to change    │
│ provider:  openrouter                      │
│ directory: ~/code/my-project               │
╰────────────────────────────────────────────╯

Codex-class agentic features

On top of the AHE harness core (which stays intact), lucid-train ships the Codex feature set:

  • update_plan — the model maintains a live step checklist, rendered in the TUI (in progress, ✓ done)
  • web_search + read_url — agentic web search (keyless DuckDuckGo→Mojeek chain, or Serper with SERPER_API_KEY); the system prompt instructs the model to verify instead of hallucinate anything it is unsure of
  • Skills — drop SKILL.md packs (Claude Code-compatible frontmatter) in ~/.lucid-train/skills/<name>/, .lucid/skills/, or even ~/.claude/skills/ — they're advertised to the agent, which reads them on demand. Install from skills.sh without leaving the chat: /skills search react queries the registry, /skills install vercel-labs/agent-skills web-design-guidelines installs it (via npx skills), and the agent can use it from your next message — the system prompt refreshes every turn
  • Thinking display — a live ✦ thinking stream while the model reasons, collapsing to a one-line summary when output starts; file-writing commands render as • Wrote src/main.rs / • Edited config.yaml instead of raw shell
  • MCP — connect any Model Context Protocol server: /mcp add github npx -y @modelcontextprotocol/server-github; tools appear to the model as mcp__github__… (approval-gated under auto)
  • Autocomplete everywhere — type / for the command palette; /download , /model , /delete continue into model names sorted best→worst with fit/size annotations (Tab to complete, ↑/↓ to choose)
  • Token accounting — live ↑ input ↓ output session counters in the footer; exec mode prints a final tokens: N in • M out line
  • Guarded full-auto — switching /approvals full-auto asks for explicit confirmation before everything auto-runs

Repo context engine

Open lucid-train inside any project (VS Code / Cursor terminal, any repo) and it maps the codebase automatically: git ls-files + symbol extraction (functions, classes, structs) chunked per file. Each turn injects only the chunks relevant to your request — keyword-scored, hard-capped at ~2k tokens — so large repos never blow the context window. The map is built once per session on a background thread.

Project memory grows with the project: the agent maintains .lucid/knowledge.md (dated architecture notes, gotchas, working commands) and .lucid/CHANGELOG.md (what changed, why, files touched), and reads them back in future sessions.

ERNIE / text-format tool-call compatibility

Some models emit tool calls as text instead of structured JSON — Baidu ERNIE's ernie_x1 format (<tool_call>{}</tool_call> + <think> blocks) and the Qwen XML style (<function=><parameter=>). Lucid Train detects and parses both transparently, so ERNIE-4.5-Thinking and quirky Qwen serving stacks can drive the harness like any other model.

Why it's good at terminal tasks

The harness is intentionally minimal — one shell tool — but wraps it in the components that won on Terminal-Bench:

  • Evolved system prompt — contract-first, mirror-the-evaluator, minimal diffs, candidate scorecards, explicit time budgets, semantic-checks-then-stop.
  • Execution risk hints — middleware watches every command and injects targeted nudges (repeated error loops, shallow validation, localhost-only checks, thin benchmark margins, missing-dependency loops, time budget burn).
  • Publish-state guard — once a final/acceptance-style check passes, destructive commands against the verified artifacts are blocked (override requires an explicit token + re-verification).
  • Context compaction — at 75% context usage the middle of the conversation is summarized into a continuation brief; emergency compaction elides old tool outputs on overflow.
  • Round & token reminders — the model always knows its iteration and context budget.
  • Background tasks — long-running servers/builds run detached with log capture (manage_background_task).

Zero-setup onboarding

lucid-train opens with no API key and no model. The setup screen detects your hardware (RAM, Apple Silicon / NVIDIA GPU) and shows which models fit:

  • Nothing to install separately/download bootstraps Ollama itself (Homebrew on macOS, install script on Linux, winget on Windows), starts the server, and then pulls your model, all inside the TUI
  • ✓ fits / ◐ fits-but-low-free-RAM / ✗ too big for every local model (Qwen3, Qwen3-Coder, Qwen2.5-Coder, DeepSeek-R1, OpenAI gpt-oss, Baidu ERNIE 4.5 Thinking, Google Gemma 3, Mistral/Devstral) — checked against both total and currently free memory
  • Research-backed recommendation per machine: gpt-oss:20b (best tool calling that fits 16 GB), qwen3-coder:30b (best agentic coder, 32 GB+), qwen3:4b for small machines; ERNIE-4.5-21B-A3B-Thinking available as a thinking specialist (hf.co/unsloth/...GGUF tag)
  • /download qwen3:4b pulls with live progress; /delete <tag> frees the disk again
  • /apikey <key> saves an OpenRouter key for cloud models
  • /login <email> creates a Lucid Cloud account for big/proprietary models (Claude, Grok, GPT-5.x, Kimi K2.5…) with pay-as-you-go credits

If you ask for a model that's too big for your RAM — or a proprietary one — lucid-train tells you and offers /login or /apikey instead of failing.

Models: open source first

Works with any OpenAI-compatible endpoint:

Where How
Local Ollama /download qwen3:4b then /model qwen3:4b — fully on-device, free
OpenRouter /apikey sk-or- — Kimi K2.5, Qwen3 Coder, DeepSeek, GLM, MiniMax, plus GPT/Claude/Gemini/Grok
Lucid Cloud /login you@email.com — hosted proxy with Stripe credits (see backend/)
Self-hosted (vLLM, llama.cpp, SGLang, TGI) lucid-train --base-url http://host:8000/v1 -m served-model-name
lucid-train models                 # list presets
lucid-train -m kimi-k2.5           # OSS frontier via OpenRouter
lucid-train -p ollama -m qwen3:4b  # fully local
lucid-train -p lucid -m claude-sonnet   # via Lucid Cloud login

Failover: set LLM_FALLBACK_MODELS=qwen/qwen3-coder,deepseek/deepseek-chat-v3.1 and the client walks the list on provider errors.

Lucid Cloud credits (backend/)

The Go backend in backend/ powers /login: email-token auth, an OpenAI-compatible SSE proxy over OpenRouter with per-request billing (provider cost + 5% margin), and Stripe top-ups where a $N purchase charges N × 1.05 × 1.18 (18% India GST on credits+margin). Without STRIPE_SECRET_KEY it runs in dev mode and credits top-ups instantly.

cd backend && ./run.sh    # listens on :8787 (set OPENROUTER_API_KEY in .env)

Install & run

cargo build --release
./target/release/lucid-train            # interactive TUI
./target/release/lucid-train exec "fix the failing tests"   # headless (CI / benchmarks)

Config file (optional): ~/.lucid-train/config.toml

model = "kimi-k2.5"
approvals = "auto"
fallback_models = ["qwen/qwen3-coder"]

Modes

  • /agent (default) — full tools; edits files and runs commands
  • /plan — propose-only: no tools run, you get a reviewed implementation plan
  • /research — web_search + read_url only: cited answers, no shell

Keys: Esc interrupts a running turn (or clears input); Esc twice quits.

Memory-friendly local inference

lucid-train starts Ollama tuned so other apps stay responsive during inference: flash attention + q8_0 KV cache (≈half the KV memory at 16k context), one model / one request at a time, and a 4-minute keep-alive so the model unloads and returns its RAM between turns. Tune via the standard OLLAMA_* environment variables if you start the server yourself.

Security & approvals

Every command is risk-assessed before it runs:

  • safe — read/build/test commands
  • caution — package installs, git push, network mutations
  • dangerous — recursive deletes, sudo, curl | sh, hard resets
  • blockedrm -rf /, fork bombs, mkfs, raw device writes — refused in every mode

Approval policies (/approvals or -a):

  • plan — propose only; every command needs your explicit y
  • auto (default) — safe commands run instantly; caution/dangerous prompt (y once / a for session / n deny)
  • full-auto — everything auto-approved except the blocked tier

TUI

  • Streaming responses with lightweight markdown, dim italic reasoning stream
  • • Ran command / └ output exec cells with duration and exit status
  • Slash commands: /model /models /provider /approvals /status /compact /new /help /quit
  • Esc interrupt • Ctrl+J newline • PageUp/mouse-wheel scroll • context % in the footer

Environment variables

Var Purpose
OPENROUTER_API_KEY default provider key
LLM_API_KEY / LLM_BASE_URL / LLM_MODEL pin any OpenAI-compatible endpoint
LLM_FALLBACK_MODELS comma-separated failover list
LUCID_TRAIN_HOME config dir (default ~/.lucid-train)

Tests

cargo test

19 unit tests (security tiers, publish guard, middleware hints, shell timeout/truncation, background tasks) + 2 end-to-end tests that run the real binary against a mock OpenAI-compatible SSE server — verifying the full model → tool-call → shell → result → answer loop, and that catastrophic commands are blocked.

Credits

Dependencies

~17–37MB
~539K SLoC