Lite SuiteLite Suite

LiteTUI

A terminal chat client and agent harness for local LLMs — streaming, tool use, vision, and per-conversation memory.

Overview

LiteTUI is a Textual terminal application that runs a full agent loop against a local model. It streams replies, renders the thinking trace in a collapsible block, calls tools until the model gives a plain answer, accepts images, and keeps each conversation's memory on disk as plain Markdown.

Nothing in LiteTUI talks to a hosted API. It was developed against qwen3.8-27B running locally on an RTX 5090.

Installation

LiteTUI is published on PyPI:

pip install litetui

Or with uv:

uv pip install litetui

Python 3.11 or newer is required. From a source checkout, uv sync then uv run --locked litetui.

Two engines, one seam

LiteTUI drives either inference backend through a single interface (src/litetui/llm_backend.py):

| engine | where | notes | |---|---|---| | lmstudio | http://localhost:1234 | Requires LM Studio's server. Load, unload, and context length go through the official lmstudio SDK rather than a shell-out. | | llamacpp | http://localhost:7470 | LiteTUI's own llama-server in router mode — one process, every chat GGUF on the box behind it. Attaches to LiteSuite's server on :8088 when that is healthy, otherwise spawns its own (detached, with a log file, killed with the app). |

/backend switches between them mid-conversation and the history survives.

Neither engine loads a model at boot, and the router runs with a concurrent-model cap so a switch cannot quietly fill your VRAM. The router's model list is generated from LiteSuite's install directory, LM Studio's directories, the HuggingFace cache and any custom roots — deduplicated, with voice and embedding GGUFs filtered out by each file's own general.architecture header rather than guessed from its name.

Conversations and memory

Every conversation gets its own directory:

.convos/<uuid>/
    convo.jsonl    append-only transcript
    memory.md      an INDEX the agent maintains
    soul.md        who it is here: preferences, standing corrections
    handoff.md     in flight / owed / absent-by-decision / caveats
    memories/      the memories themselves, one file per idea

The agent is told its own uuid and absolute path in the system prompt. memory.md, soul.md and handoff.md are injected once, into the system message at the start of the conversation — a snapshot, not a live view. They are not re-sent every turn: three files on every request is affordable at a million tokens of context and is not on a local 27B, where it crowds out the conversation. To see current contents the agent reads them with the read tool. Index lines are capped at roughly 50 tokens each: pointers, never the memory itself.

The transcript is append-only

convo.jsonl is never rewritten and never backed up and replaced. A torn append costs one line, which the reader tolerates; a failed rewrite costs the conversation. Records apply in file order:

| type | effect | |---|---| | meta | id / created / model | | msg | one message, verbatim | | edit | replace ONE message in place | | truncate | drop a head range, splice new messages in front | | snapshot | whole list (read for older files; no longer written) |

/compact records a truncate rather than a fresh copy of everything. Measured on a 30-message conversation: 303 bytes instead of 5,445 — and the raw history stays on disk behind the marker.

Tools

Fifteen tool schemas ship with LiteTUI, several of them policy-gated so a tool can be withheld at the schema door rather than refused after the call. Results are capped at 2,000 lines / 50KB. Toggle the whole loop with Ctrl+T.

ask_user_question · bash · chrome · edit · grep · harness · listen · pccontrol · powershell · read · skill · studio · view_image · web_fetch · write

Three of them were built by LiteTUI itself

The seat that built its own tools runs qwen3.8-27B locally. grep and edit were designed by Sentinel and Ryan and written by LiteTUI's own agent seat. grep invokes ripgrep as an argv list with no shell anywhere; edit performs exact-byte replacements through a read-before-edit guard and writes atomically via tmp + replace. They landed with tests/test_file_tools.py at 24 of 24 green and the full suite at 1,481 passed, 6 xfailed, 0 failed.

The listen tool — audio perception via a local Qwen2-Audio model on a standalone llama-server — came the same way from a second seat, including a loudness guard that bails before doing any work when a clip is effectively silent, because the model never volunteers "I hear nothing".

Vision

Paste an image with Ctrl+O, or give a path — quoted or bare, with or without a question after it:

C:\shots\screen.png what is the error in this dialog?
"C:\My Folder\screen.png"

A model can only see images if the backend reports it as a VLM. A GGUF shipped without an mmproj projector loads as a plain LLM and returns HTTP 400 on image input; the fix is to place a matching mmproj-*.gguf beside the weights.

Commands

| | | |---|---| | /new /clear | start a new conversation (new folder on disk) | | /system <text> | set the system prompt | | /model [n] | show or switch model | | /backend | switch engine — LM Studio or llama.cpp. The conversation survives | | /load /unload | put a model into memory, or free it | | /modelcfg | per-model Info / Load / Inference screen | | /think [level] | off · minimal · low · medium · high · xhigh · unset | | /compact [hint] | summarise older messages, keep the last 4 | | /convos | list saved conversations with sizes | | /resume <n\|id> | load one (id = uuid prefix) | | /reconnect /quit | |

Esc stops the current turn (it asks first; Esc again forces). Ctrl+O paste image · Ctrl+X clear image · Ctrl+L new conversation · Ctrl+T tools.

/modelcfg

Three tabs per model — Info, Load, Inference. Load covers context length, GPU offload, threads, batch sizes, parallel slots, flash attention, KV cache quantization, mlock/mmap, RoPE, seed, a draft model for speculative decoding, a vision mmproj, and the chat template. Inference layers per-model sampling over your global settings, plus structured output and named presets.

The two engines do not expose the same knobs. A control the active engine cannot drive renders greyed with the reason attached — never silently absent.

A seat in the fleet

LiteTUI registers itself with LiteHarness and carries a harness tool, so it sends and receives inter-agent inbox messages like any other agent seat — a local model in a terminal, taking assignments alongside the hosted ones.