No description
  • Rust 99.4%
  • Dockerfile 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Thomas Forgione 1062eb4e57
Bring the view back when a tool asks to run
Leaving a reader where they are is right for an answer arriving and wrong
for a question. What is being agreed to is the call box at the bottom —
draw_confirm rests on that, and so does the doc comment on ask itself —
so a confirmation raised while somebody is reading further up asks about
something that is not on screen. Seen as "Run this tool?" with ↑73 on the
bar and no preparing run_shell anywhere.

App::ask is the one place allowed to take the view off a reader. The test
scrolls up before the round and asserts the question brought it back; it
fails without the two lines, which is the only reason to trust it.
2026-09-17 10:11:38 +02:00
src Bring the view back when a tool asks to run 2026-09-17 10:11:38 +02:00
.dockerignore Give the model a shell, and a container to use it in 2026-09-11 13:32:12 +02:00
.gitignore Give the model a shell, and a container to use it in 2026-09-11 13:32:12 +02:00
Cargo.lock Let the model search the web and read a page 2026-09-15 11:35:00 +02:00
Cargo.toml Let the model search the web and read a page 2026-09-15 11:35:00 +02:00
CLAUDE.md Bring the view back when a tool asks to run 2026-09-17 10:11:38 +02:00
Dockerfile Give the model a shell, and a container to use it in 2026-09-11 13:32:12 +02:00
LICENSE Ready the crate for crates.io: GPL-3, metadata, 0.0.1 2026-09-10 18:18:42 +02:00
README.md Show a model's thinking, and count it 2026-09-11 09:47:48 +02:00
run.sh Give the model a shell, and a container to use it in 2026-09-11 13:32:12 +02:00

papote

Fully vibe-coded. Every line of this was written by an LLM, reviewed only as far as a conversation allows. Use at your own risk.

A terminal chat with a local LLM whose answers are formatted while they stream in — headings, tables, boxed code with syntax highlighting, all re-wrapped live as the answer grows.

 Explain TCP briefly, with a code block and a table.

TCP (Transmission Control Protocol) is a transport-layer protocol that
guarantees reliable, ordered delivery between two hosts.

╭─ rust ───────────────────────────────────────────────────────────────────────╮
│ use std::net::TcpStream;                                                     │
│ let mut stream = TcpStream::connect("127.0.0.1:8080")                        │
│     .expect("cannot connect");                                               │
╰──────────────────────────────────────────────────────────────────────────────╯

┌────────────────┬───────────────────────────┬────────────────────────────┐
│ Property       │ TCP                       │ UDP                        │
├────────────────┼───────────────────────────┼────────────────────────────┤
│ Reliability    │ Guaranteed (retransmits)  │ Best-effort                │
│ Mode           │ Connection-oriented       │ Connectionless             │
└────────────────┴───────────────────────────┴────────────────────────────┘

Getting started

You need an OpenAI-compatible server that streams SSE — typically llama-server. http:// and https:// both work, and endpoints behind HTTP basic auth are supported.

cargo install --git https://git.tforgione.fr/tforgione/papote
papote

Nothing is configured out of the box. The first run asks for an endpoint, then lists the models it offers and lets you pick one, and writes both down.

What it does

  • Renders markdown as it arrives: headings, lists, quotes, tables aligned to the terminal, boxed code blocks coloured for a dozen languages, clickable links.
  • Full-screen: the conversation scrolls, the input box grows with your message, and resizing re-wraps everything mid-answer.
  • Saves every conversation, names it by asking the model, and /resume picks one back up where you left it — or papote --private for one that is never written down.
  • Talks to several endpoints — /provider and /model switch between them without restarting.
  • /system sets the system prompt, shown at the top of the conversation and saved with it.
  • /image ~/Images/moi.jpg hangs a picture on the input line, to ask your question beside it; /model says which models can see. A picture copied in a file manager can be pasted in, and Ctrl-V attaches a screenshot straight off the clipboard.
  • The model can ask papote for what it cannot know: get_datetime gives it the local time, and the call and its answer show in the conversation.
  • A model that thinks before answering has its thinking streamed, shown and counted, rather than a still screen and a silent bar.
  • Tab completes the commands and the path of an image, then walks the candidates one press at a time, the one in the line highlighted on the bar.
  • Ctrl-C stops an answer that has gone off the rails and keeps what arrived.

Commands

/resume carry on with a saved conversation
/image <path> attach a picture to your next message
/system set the system prompt, or drop it
/rename name it, or let the model find one
/model, /provider switch model or endpoint
/clear start a new conversation
/help the rest of them

Documentation

The details live in the wiki:

Development

cargo test && cargo clippy --all-targets && cargo fmt

See CLAUDE.md for the invariants worth knowing before changing the renderer or the display.