Metadata-Version: 2.5
Name: agentknit-tui
Version: 0.1002.0
Summary: Textual TUI front-end for agentknit coding agents.
Project-URL: Homepage, https://github.com/monperrus/agentknit-tui
Project-URL: Repository, https://github.com/monperrus/agentknit-tui
Project-URL: Issues, https://github.com/monperrus/agentknit-tui/issues
Project-URL: Changelog, https://github.com/monperrus/agentknit-tui/blob/main/CHANGELOG.md
Author: agentknit contributors
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.11
Requires-Dist: agentknit<1,>=0.2.0
Requires-Dist: rich>=13
Requires-Dist: textual>=0.86
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest-cov>=4; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# agentknit-tui

A [Textual](https://textual.textualize.io/) TUI front-end for
[agentknit](https://github.com/monperrus/agentknit) coding agents.

Features unique to this harness (things Claude Code and Codex do not do):

- **Side questions.** Type while a turn is running and the prompt is
  answered as a *side question* — a separate read-only LLM call over a
  snapshot of the conversation, rendered next to the turn without
  touching the turn's context or progress.
- **Token-budget countdown at deciles.** The agent runs under a hard
  token budget; the log prints `remaining/budget` only when usage
  crosses into a new 10% band, instead of nagging after every call.
- **Read-through streaming.** Scrolling up detaches the view from the
  end: the agent keeps streaming into the log, but nothing yanks you
  back down. Scrolling to the bottom re-attaches the follow.
- **Paste-safe rendering.** No `│` gutters, no box-drawing borders, no
  right-hand padding on any rendered line — copying a selection (or a
  whole block) yields the payload text exactly.
- **Per-folder prompt history shared with the REPL.** The TUI and the
  agentknit REPL read and write the same per-directory history file, so
  `↑` recalls prompts typed in either front-end, scoped to the folder
  they were typed in.
- **Quota vs rate-limit labeling.** HTTP 403 is reported as "Quota"
  (exhausted window), 429 as "Rate limited" — providers that use 403
  for quota are not misreported.
- **Clipboard that works in VTE terminals.** Copy tries the platform
  tool (`xclip`/`xsel`, `wl-copy`, `pbcopy`, `clip.exe`) *and* emits
  OSC 52; one of the two reaches the system clipboard even in terminals
  (Terminator, older gnome-terminal) that ignore OSC 52.
- **Word-level diff highlighting.** `str_replace` edits render as
  colorized unified diffs with the changed *words* inside each modified
  line bolded on a dark background — a one-word change in a long line
  is visible at a glance. Copied diff lines paste clean.

Everything else is standard TUI furniture: one conversation pane, a
multiline prompt, tool calls/results/token accounting inline, a live
status bar. The TUI is a pure subscriber to the event stream from
agentknit.

## Install

```
pip install agentknit-tui
```

It depends on `agentknit`, `textual`, and `rich`.

## Usage

```
agentknit-tui                       # default: glm-5.2 via z.ai
agentknit-tui glm-5.2
agentknit-tui "qwen3-8b" "https://openrouter.ai/api/v1"
agentknit-tui --session <id>        # resume a previous trajectory
agentknit-tui --non-interactive     # drop ask_user* tools from the schema
agentknit-tui --no-strict-cache-proof
```

### Key bindings

| key                  | action                          |
| -------------------- | ------------------------------- |
| `Enter`              | submit the prompt               |
| `Shift/Ctrl/Alt+Enter` | insert a newline              |
| `↑` / `↓`            | recall past prompts (same folder, shared with the REPL) |
| `Esc` / `Ctrl+C`     | cancel the running turn (or quit when idle) |
| `Ctrl+Shift+C`       | copy the mouse selection in the log          |
| `Ctrl+L`             | clear the on-screen conversation log only |

While reading: scrolling up (mouse wheel, or `PageUp` with the prompt
focused) detaches the view from the end — new messages keep arriving in
the log but no longer pull you back down, so you can keep reading while
the agent works. Scrolling back to the bottom re-attaches the
auto-follow. `PageDown` pages down and snaps to the end when a page
away.

### Mouse

- **Drag** over the conversation log selects text in place (highlighted as
  you drag); `Ctrl+Shift+C` then copies the selection (plain `Ctrl+C` also
  works when your terminal delivers it). `Esc` clears the selection.
- Paste into the prompt with the terminal's own paste (`Ctrl+Shift+V`,
  `Shift+Insert`, or middle-click) — `Ctrl+V` inside the TUI only reads
  text copied *within* the TUI.
- Copying tries the platform clipboard tool first (`xclip`/`xsel`, `wl-copy`,
  `pbcopy`, `clip.exe`) and also emits OSC 52; one of the two reaches the
  system clipboard even in VTE terminals that ignore OSC 52 (Terminator,
  older gnome-terminal).
- Every line the TUI renders is paste-safe: turns, replies, diffs and tool
  output carry no `│` gutters or box-drawing borders, and no right-hand
  padding — copying a selection (or a whole block) yields the payload text
  exactly. Copied lines are trimmed of any trailing filler.

`Ctrl+L` (and the TUI's built-in `/clear` alias) wipes the displayed log
and zeroes the token counters in the status bar; the agent's message
history — the context sent to the model — is untouched, and `/usage`
still reports the session's full totals.

### Status bar

The line under the prompt always shows the model, working directory, and
total tokens in the format `<model> - <working directory> - <tokens>`.
While a turn is running, the task the agent is working on appears below it,
wrapped over two terminal-width lines so long prompts stay readable.
To reset the LLM context (session history, keeping the system prompt), run
`/reset-context` in the TUI; it forwards to agentknit's `/clear` handler.

Slash commands (`/help`, `/usage`, `/clear`, `/compact`, `/model`, `/reset-context`, `/exit`)
are forwarded to agentknit's command registry; their printed output is
captured and shown inline.

### `str_replace` diffs

Edits made through the `str_replace` tool are shown as a colorized unified
diff instead of the tool's argument dump: deleted lines in red, added lines
in green, and the specific changed *words* within each modified line
highlighted in bold on a dark background, so a one-word change inside a long
line is visible at a glance. Each row carries the file's real line number
plus the `+`/`-` marker, separated from the content by spaces only — no
vertical-bar gutter, so copied diff lines paste clean.

```diff
--- pkg/mod.py
+++ pkg/mod.py
@@ -1,4 +1,4 @@
-def greet(name):
-    # say hello to the user
-    print("hello " + name)
+def greet(name, greeting="hi"):
+    # greet the user
+    print(greeting + " " + name)
     return None
```


On exit the TUI prints the command to resume the session on the console,
exactly like the end of the agentknit REPL:

```
Resume: agentknit-tui glm-5.2 --session <session-id>
```

Set `AGENTKNIT_RESUME_COMMAND` to override the program prefix (wrappers
embedding the model already do this); the `--session <id>` suffix is always
appended.

## Design notes

- The agent loop (`agentknit.run_turn`) is synchronous and blocking and
  emits typed events through a session `on_event` callback. The TUI runs
  each turn in a Textual worker thread and forwards every event onto a
  thread-safe queue; a 50 ms UI-thread timer drains the queue and renders
  each event's pre-formatted ANSI string into a Rich renderable.
- agentknit's `fmt` strings are raw `\033[…]` ANSI escapes (not Rich
  markup), so they are decoded with `rich.ansi.AnsiDecoder` for faithful
  colour/style reproduction.
- Multi-line input uses `TextArea`, so users can paste and edit freely.
  A `CancelToken` is wired to the cancel bindings so a turn can be
  interrupted cooperatively, exactly like Ctrl+C in the REPL.
- Prompt history is per-folder and shared with the REPL: both read and
  write agentknit's readline history file
  (`~/.local/share/agent_probe/repl_history/<md5(cwd)>.hist`), so arrow-up
  recalls instructions typed in either front-end, scoped to the folder they
  were typed in. `↑` on the first prompt line walks back, `↓` forward, and
  any edit drops back to normal typing.
- On exit the TUI mirrors the REPL's teardown: the trajectory snapshot is
  saved (if the session has any messages), a `session_end` record is
  appended to the session log, and — after Textual restores the plain
  console — the same dim `Resume: …` line the REPL prints is echoed so the
  session can be continued with `--session <id>`.
- agentknit installs a module-level SIGINT handler (meant for the
  foreground REPL) that kills the active tool subprocess. The TUI
  neutralises it for each turn's duration and drives cancellation through
  the `CancelToken` instead.

## License

MIT.
