oolong

command module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 16 Imported by: 0

README ΒΆ

Oolong 🍡

CI

Simple ephemeral chat β€” a fast, keyboard-driven terminal client for OpenAI models, built with Bubble Tea.

  • Ephemeral by design β€” conversations live in your terminal and nowhere else. Nothing is written to disk unless you save a transcript, and OpenAI's server-side response storage is switched off. Close the window and the chat is gone.
  • Any OpenAI-compatible endpoint β€” the official API works out of the box, or point base_url at Ollama, LM Studio, or OpenRouter and give local models the same polished UI.
  • Scriptable β€” git diff | oolong "write a commit message" streams the answer straight to stdout, no TUI, so Oolong drops into any shell pipeline.

oolong demo

Features

  • Streaming responses rendered as markdown with syntax-highlighted code blocks
  • Ephemeral by design β€” history is kept in memory only, and requests are sent with response storage disabled on OpenAI's side
  • Model picker with per-model pricing, plus a live token count and cost estimate in the chat header
  • Mid-chat model switch β€” esc back to the picker keeps the conversation, so you can escalate to a bigger model halfway through
  • Image input β€” paste an image from the clipboard (ctrl+v) and it's attached to your next message
  • File attachments β€” ctrl+f picks an image or text file from disk to send with your next message
  • One-shot mode β€” oolong "question" (or cat main.go | oolong "explain") streams the answer to stdout with no TUI, so Oolong works in scripts and pipelines
  • OpenAI-compatible endpoints β€” point base_url at Ollama, LM Studio, OpenRouter, or any compatible server, globally or per model
  • Context meter β€” the chat header tracks how much of the model's context window the conversation fills, and warns as it nears the limit
  • System prompt editing in place (ctrl+p), without losing your message draft
  • Transcript export & resume β€” ctrl+s saves the conversation as a timestamped markdown file; oolong --resume <file> picks it back up later
  • Configurable β€” an optional TOML config file sets a custom model catalog, a default model, reasoning effort and verbosity, endpoints, transcript directory, and accent color
  • Keychain storage β€” your API key lives in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service), not in a dotfile
  • Readable math β€” LaTeX in responses is converted to plain Unicode instead of showing up as mangled backslashes

Install

Homebrew (macOS)
brew install --cask dicedatalore/tap/oolong
With Go
go install github.com/dicedatalore/oolong@latest

Works on macOS, Linux, and Windows with Go 1.26+. Clipboard image paste needs cgo β€” a C compiler, plus the X11 development headers on Linux:

sudo apt install libx11-dev   # Debian/Ubuntu

Without cgo the build still works; image paste is simply disabled.

From source
git clone https://github.com/dicedatalore/oolong.git
cd oolong
go build
./oolong

Prefer a standalone binary? Prebuilt archives for macOS, Linux, and Windows are on the releases page. On Windows, run Oolong from Windows Terminal β€” the legacy console doesn't render TUIs well.

Getting started

  1. Run oolong.
  2. On first run, paste your OpenAI API key. It's validated against the API (no tokens spent) and saved to your OS keychain. Alternatively, set OPENAI_API_KEY in your environment β€” it takes precedence over the keychain.
  3. Pick a model and start chatting.

To remove a stored key: press ctrl+k on the model picker, or run oolong --reset-key.

Configuration

Oolong is fully usable with no configuration. To customize it, run oolong config init to scaffold a commented ~/.config/oolong/config.toml ($XDG_CONFIG_HOME is respected); every key is optional:

default_model = "gpt-5.6-terra"   # skip the picker on launch
transcript_dir = "~/notes/chats"  # OOLONG_TRANSCRIPT_DIR still wins
accent = "#FFAF87"                # primary accent color
# base_url = "http://localhost:11434/v1"  # any OpenAI-compatible endpoint

# Replaces the built-in model catalog when present. Any model your API key
# can access works β€” entries are checked against the API and unavailable
# ones are hidden from the picker.
[[models]]
id = "gpt-5.4"
description = "Previous generation"
input_rate = 1.25    # USD per 1M tokens, both optional
output_rate = 10.00
reasoning_effort = "medium"  # gpt-5.6 takes none | low | medium | high | xhigh
verbosity = "low"            # low | medium | high
context_window = 400000      # tokens; shows a ctx meter in the chat header
# base_url = ""              # per-model endpoint, overrides the global one

For a single run, oolong --model <id> opens a chat directly with any model your key can access, overriding default_model.

reasoning_effort and verbosity set the model's default Responses API parameters. They're passed through as-is β€” the supported values vary by model generation, and the API reports clearly if a model rejects one. On the model picker, ←/β†’ adjust the selected model's effort for the session, shown in the list item and later in the chat header. A malformed config never blocks launch β€” Oolong falls back to defaults and shows what it ignored.

OpenAI-compatible endpoints

base_url points Oolong at any server that speaks the OpenAI API β€” Ollama, LM Studio, OpenRouter, and friends. Set it globally, or per model to mix endpoints in one catalog. Local endpoints need no API key; on custom endpoints Oolong skips the OpenAI-specific key validation and model availability check. The OPENAI_BASE_URL environment variable overrides every configured endpoint.

Scripting

Positional arguments (or piped input) skip the TUI entirely and stream the answer to stdout:

oolong "why is the sky blue"
cat main.go | oolong "explain this file"
git diff | oolong "write a commit message"

One-shot mode uses --model / default_model (falling back to the catalog's first entry) and the same key, endpoint, and reasoning settings as the TUI.

Resuming a chat

Transcripts saved with ctrl+s can be picked back up later:

oolong --resume oolong-chat-2026-07-19-094035.md

The conversation, system prompt, and model are restored from the file (image and file attachments are recorded only as labels, so they don't ride along). Nothing is ever loaded implicitly β€” resume only reads a file you name.

Keybindings

Key Action
enter Send message
shift+enter / ctrl+j Insert newline
ctrl+v Paste (a clipboard image becomes an attachment)
ctrl+f Attach an image or text file from disk
ctrl+e Compose the message in $EDITOR
ctrl+y Copy the last reply to the clipboard
ctrl+b Copy the last reply's last code block
ctrl+r Regenerate the last reply
↑ / ↓ Cycle through your sent messages, attachments included (when the composer is empty)
ctrl+n Start a new chat
ctrl+p Edit the system prompt
ctrl+s Save transcript to markdown
pgup / pgdn Scroll the conversation
home / end Jump to top / bottom
esc Stop a streaming response, or switch model (the conversation is kept)
ctrl+c Quit
? Toggle full help

On the model picker, ←/β†’ adjust the selected model's reasoning effort before the chat starts, and esc clears an active filter before it quits.

The mouse wheel scrolls the conversation too; hold shift while dragging to select text, as usual in TUIs.

Note: shift+enter requires a terminal with keyboard enhancement support (Kitty, Ghostty, WezTerm, foot, …). ctrl+j works everywhere.

Privacy

  • Your API key is stored in the OS keychain, never in a plain-text file.
  • Chat history exists only in process memory unless you save it with ctrl+s.
  • Requests are sent with store: false, so OpenAI does not retain responses for the Responses API's server-side history.

Development

go test ./...

The UI is a Bubble Tea state machine with three screens β€” model picker, chat, and first-run key entry β€” each in its own file under internal/ui. Supporting packages: internal/openai (streaming client), internal/keystore (keychain), internal/mathfmt (LaTeX β†’ Unicode), and internal/clipboard (image paste).

Releases are cut automatically on push to main: the version bump is derived from conventional commit messages β€” feat: β†’ minor, fix: β†’ patch, a breaking change β†’ major β€” and commits of other types (chore:, docs:, test:, …) don't trigger a release.

License

MIT

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
internal
clipboard
Package clipboard reads image attachments from the system clipboard.
Package clipboard reads image attachments from the system clipboard.
config
Package config loads Oolong's optional TOML config file from ~/.config/oolong/config.toml (or $XDG_CONFIG_HOME/oolong/config.toml).
Package config loads Oolong's optional TOML config file from ~/.config/oolong/config.toml (or $XDG_CONFIG_HOME/oolong/config.toml).
keystore
Package keystore stores the OpenAI API key in the OS keychain.
Package keystore stores the OpenAI API key in the OS keychain.
mathfmt
Package mathfmt converts LaTeX math in markdown to plain Unicode text.
Package mathfmt converts LaTeX math in markdown to plain Unicode text.
openai
Package openai wraps the OpenAI SDK in a minimal streaming chat client.
Package openai wraps the OpenAI SDK in a minimal streaming chat client.
ui
Package ui implements the Oolong terminal user interface.
Package ui implements the Oolong terminal user interface.
version
Package version reports the app version shown in the banner and by the -version flag.
Package version reports the app version shown in the banner and by the -version flag.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL