Metadata-Version: 2.4
Name: lithe-cli
Version: 0.6.0
Summary: Command-line interface for the lithe agent kernel: chat, one-shot runs, undo, and run inspection.
License: MIT License
        
        Copyright (c) 2026 betaloop contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Keywords: agent,llm,react,cli,tool-calling
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: lithe>=0.9.8
Requires-Dist: prompt-toolkit>=3.0.38
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Dynamic: license-file

# lithe-cli

[![PyPI](https://img.shields.io/pypi/v/lithe-cli.svg)](https://pypi.org/project/lithe-cli/)
[![Python](https://img.shields.io/pypi/pyversions/lithe-cli.svg)](https://pypi.org/project/lithe-cli/)
[![License: MIT](https://img.shields.io/pypi/lithe-cli.svg)](https://pypi.org/project/lithe-cli/)

**lithe-cli** is the command-line interface for
[lithe](https://pypi.org/project/lithe/) — the storage-free ReAct agent
kernel. Installing it pulls in `lithe` automatically and gives you a `lithe`
command: chat with an agent that reads and writes files in your workspace,
runs code, searches the web through MCP tools, inspects stored runs, and
undoes a run's mutations.

```bash
pip install lithe-cli
```

## Configure

There is no default endpoint — the CLI refuses to run rather than silently
hitting some third-party URL. The easiest way in is the wizard: on the
first `lithe chat` / `lithe run` (or any time, via `lithe config`) an
interactive terminal prompts for the three essentials and saves them to
`$LITHE_HOME/config.json` (mode 0600 — it holds the key). An optional
connectivity probe catches typos before your first turn.

To configure by hand instead, point the CLI at any OpenAI-compatible
endpoint:

```bash
export LITHE_API_KEY=sk-...
export LITHE_BASE_URL=https://your-endpoint/api/v1
export LITHE_MODEL=your-model
```

Resolution order is flag (`--api-key`, `--base-url`, `--model`) >
environment > saved config file, per key. The wizard never runs without
a TTY on both ends, so pipes and CI keep the hard refusal; `--no-setup`
restores that fail-fast behavior on terminals too. `lithe config --show`
peeks at the saved values with a masked key.

`LITHE_HOME` (default `~/.lithe`) locates the run store; the agent's
workspace defaults to the current directory (`--workspace` to change).

`lithe doctor` prints the effective configuration — endpoint (with a
masked key), config file, store, workspace, sandbox backend, skills, MCP
servers — so you can see what a run would use before starting one.

## Use

### One-shot task

```bash
$ cd my-project
$ lithe run "总结 README.md 的要点，存到 SUMMARY.md"
  ⚒ read_file {"path": "README.md"}
  ✓ 已读取 README.md（120 行） 0.1s
  ⚒ write_file {"path": "SUMMARY.md", "content": "..."}
  ✓ 写入 SUMMARY.md 0.0s
已把要点写入 SUMMARY.md。
── done · steps 3 · tokens 2100 · cost 0.0042
```

`--stream` streams tokens as they generate; `-v` adds per-call
usage/context gauges; `--max-steps` caps the tool loop;
`--context-window` enables fullness gauges.

### Full-screen interface

On an interactive terminal, `lithe chat` and `lithe run TASK` open a
persistent full-screen interface instead of scribbling one-line events
into the console:

```text
 lithe 0.6.0 · your-model · /home/me/my-project      ● 完成 · 0.2s
┌─ 对话 ──────────────────────────────┐┌─ 运行状态 ─────────┐
│ 把 a.txt 改成三行待办清单            ││ ● 完成 · 0.2s      │
│ ⚒ update_todos {"todos": [...]}     ││ 步骤 2/35 · 0.2s   │
│ ✓ 任务清单已更新（3 条） 0.0s        ││ ✓ update_todos 0.0s│
│ ⚒ write_file {"path": "a.txt"}      ││ ✓ write_file 0.0s  │
│ ✓ 写入 a.txt 0.0s                   ││ ── 待办 1/3        │
│ 已完成。                             ││ [~] 修改 a.txt     │
│                                     ││ ── 用量            │
│                                     ││ tokens 1,240       │
└─────────────────────────────────────┘└────────────────────┘
lithe ❯ _
 ● 完成 · step 2/35 · 1,240 tok · $0.0021    Enter 发送 · /help 命令
```

The left pane is the conversation (task, tool calls and outcomes, the
streaming assistant reply); the right sidebar shows run status, step
budget and elapsed time, recent tool calls with duration, the agent's
todo list (updated live as the agent rewrites it), and running token /
cost / context totals. The screen stays up between turns — a finished
run does not dump you back into the raw console. `Ctrl+C` cancels the
current turn while running and exits when idle; in `lithe run` mode the
result stays on screen until you press `q`. Layout, wrapping and
alignment are East-Asian-width aware; narrower terminals stack the two
panes vertically. Pipes and CI keep the plain per-line output unchanged.

History carries across turns within a session (each turn is its own run
in the store, replayed as context for the next). `/new` clears the
session, `/tools` lists the registered tools, `/help` lists the commands.

### Extra capabilities

The kernel ships these as bundles; the CLI grants them per flag:

| Flag | Tools granted | Notes |
| --- | --- | --- |
| `--code` | `run_code` / `run_file` | Python under bubblewrap when installed (passthrough otherwise); `doctor` shows which |
| `--shell` | `run_command` | Native bash/sh on Linux and macOS, PowerShell/cmd on Windows; runs with the current user's host permissions, is not sandboxed, and cannot be undone |
| `--skills DIR` | `load_skill` | markdown skill library; defaults to `$LITHE_HOME/skills` when it exists, `--skills ""` disables |
| `--download` | `download_file` | SSRF-guarded, size-capped network fetch |
| `--vision` | `image_info` / `analyze_image` | image probe is stdlib-only; analysis routes one vision call to the main endpoint |
| `--mcp SPEC` | whatever the servers expose | JSON array/object or `@file` (env `LITHE_MCP`); stdio and streamable-http; failed servers degrade gracefully |

```bash
$ lithe run --code "用 run_code 验证 results.csv 的行数"
$ lithe run --shell "检查当前目录的项目状态"
$ lithe chat --skills ~/my-skills --mcp @~/mcp.json
```

### Undo a run

The bundled file and todo tools register reverters, so undo works with zero
configuration:

```bash
$ lithe runs                     # find the run
run           status  steps  cost  task
────────────  ──────  ─────  ────  ────────────────
abc123def456  done    3      0.01  总结 README.md …
$ lithe undo abc123def456
✓ 已撤销 2 个操作（run abc123def456）
```

A file the run created is deleted; a file it overwrote is restored.
(`run_code` side effects are not revertible — its tool description warns
the model.)

### Inspect

```bash
$ lithe runs                     # stored runs (newest last)
$ lithe log abc123def456         # messages + actions of one run
$ lithe doctor                   # config + capability status
```

### Tools

```bash
$ lithe tools                    # what the agent can do
tool          category  description
────────────  ────────  ──────────────────────────────
apply_patch   WRITE     以行级 patch 一次修改多个文件…
read_file     READ      读取文件内容…
...
```

The default tool set is the workspace bundle (`read_file` / `write_file` /
`edit_file` / `list_files` / `search_files` / `glob_files` /
`apply_patch`) plus todos (`update_todos` / `list_todos`); the flags above
add capabilities. (MCP tools attach at run time, so `lithe tools` lists
them only after a session has started the servers.)

### Colors

Output is colored when stdout is a TTY and `NO_COLOR` is unset; `--color`
/ `--no-color` force either way. Output rendering itself stays
dependency-free — plain text degrades cleanly through pipes and cron.
Interactive *input* (the chat prompt and the setup wizard) is
[prompt_toolkit](https://python-prompt-toolkit.readthedocs.io/):
wide-character-safe editing, bracketed-paste handling, star-echoed API
keys, inline wizard validation, and persistent history.

## Where things land

| Path | Contents |
| --- | --- |
| current dir (or `--workspace`) | the agent's sandboxed workspace — every tool path resolves strictly inside it |
| `~/.lithe/runs` (or `--store`) | JSONL run store: messages, actions, undo records |
| `~/.lithe/runs/todos-<user>.json` | the agent's task list |
| `~/.lithe/skills` (or `--skills`) | the markdown skill library, when enabled |
| `~/.lithe/history` | chat input history (prompt_toolkit `FileHistory`; Up/Ctrl+R recall) |

## Design notes

- The CLI is a thin host: it supplies tools, a system prompt, and the
  kernel's `JsonlRunStore`; everything else (ReAct loop, streaming, budgets,
  replay, undo engine) is reused from lithe.
- End-to-end behavior is tested offline against a scripted transport — no
  test spends tokens.
- `python -m lithe_cli` works alongside the `lithe` console script.

## License

MIT
