Metadata-Version: 2.4
Name: kortalk
Version: 1.0.0
Summary: Korvus AI chat for Linux: persistent multi-turn dialogs with Claude, OpenAI-compatible and local models, plus a quick popup for selected text. Tray, streaming, two languages.
Author: Ivan Cherniy
License: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/r4ven-me/kortalk
Project-URL: Website, https://r4ven.me
Keywords: ai,chat,dialog,korapps,korvus,claude,openai,ollama,clipboard,popup,qt,tray
Classifier: Environment :: X11 Applications :: Qt
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Desktop Environment
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PySide6>=6.5
Requires-Dist: anthropic>=0.40
Requires-Dist: PyYAML>=6.0
Requires-Dist: Markdown>=3.5
Requires-Dist: Pygments>=2.17
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Requires-Dist: pytest-qt>=4; extra == "test"
Requires-Dist: httpx; extra == "test"
Dynamic: license-file

# kortalk

**Korvus AI chat** — part of the **korvus** family apps.
A desktop AI chat for Linux: persistent multi-turn dialogs with Claude,
OpenAI-compatible or local models, with session history, file/image
attachments and in-conversation search. Lives in the tray, streams
responses as they arrive. For a quick one-off question, a lightweight
popup — in the spirit of [Crow Translate](https://crow-translate.github.io/)
— answers on selected text right near the cursor instead of opening the
full window.

## Features

- **Dialog window** — the main surface: a session list of saved
  conversations next to a single thread that keeps full multi-turn
  context (every earlier turn is resent to the provider), `Ctrl+Enter` to
  send, `Ctrl+F` to search the conversation (text and code blocks alike).
  A pinned "Quick questions" entry is always there too, for one-off
  messages that shouldn't accumulate context or get saved between
  restarts. Paste (`Ctrl+V`), drag and drop, or use the 📎 button to
  attach images and text files — they go to the model with your next
  message, on every provider including Claude Code CLI; click an image to
  open it full-size. A prompt's own provider/model choice (see "Prompt
  library" below) never overrides what's picked here.
- **AI providers**:
  - **Claude Code CLI** — via `claude -p`, no API key (default);
  - **Anthropic API** — official SDK, streaming (API key required);
  - **OpenAI-compatible APIs** — OpenAI, **Ollama**, LM Studio, OpenRouter,
    Groq, DeepSeek and any other service with `/chat/completions`
    (configured with `base URL` + model + key; local servers need no key).
- **Prompt library** — any number of named prompts in Settings, each with
  its own global hotkey and reachable from the tray submenu; one is
  marked as the default. A prompt can pin its *popup* to a specific
  provider/model, overriding whatever provider is active — handy for
  keeping a fast/cheap model on one hotkey and a stronger one on another
  — without touching the provider selected in the dialog window.
- **Popup near the cursor** — a quick, secondary way to get a one-off
  answer on selected text without opening the dialog window: select text
  with the mouse → press a hotkey → a small window with the streamed
  response appears right there. Rounded corners, Markdown rendering with
  highlighted code blocks, text selection/copying, draggable by the mouse
  and resizable from its edges. Always opens at the size configured in
  Settings; a manual resize sticks for that popup instead of snapping
  back as the answer keeps streaming in. Stays on top of every other
  window and only closes via its own ✕ button — losing focus or clicking
  outside it does nothing.
- **Tray** — the application is resident: a monochrome raven icon (Corvus
  — the korvus emblem), left click = open the dialog window, a menu with
  the prompt library, a popup with the selection, settings and quit.
- **Global hotkeys inside the application** — one prompt-to-key table in
  Settings → Prompts: each prompt has its own hotkey that opens the popup
  with that prompt and the current selection (the default prompt,
  "Explain", ships with `Ctrl+Alt+C`), plus a separate hotkey to open the
  dialog window (`Ctrl+Alt+W` by default). X11 — direct XGrabKey
  interception, Wayland — the system GlobalShortcuts portal. No external
  tools or DE configuration required.
- **Graphical settings** — prompts, hotkeys, theme, font, popup sizes,
  timeouts, a provider manager with keys, autostart at login, deleting
  all saved dialogs. The config is human-readable YAML
  (`~/.config/kortalk/config.yaml`).
- **Theme and fonts** — follows the environment theme (Qt) by default,
  optionally Nord Dark / Nord Light. The tray icon's own colour follows
  that same theme by default too, or can be pinned to dark/light
  regardless of it (Settings → General → "Tray icon") — the system tray's
  own background isn't always the same as the app's theme.
- **Two interface languages** — English (default) and Russian:
  Settings → General → Language.
- **PRIMARY selection is read natively** via Qt — xclip/xsel/wl-clipboard
  are not needed. Works on X11 and Wayland.

## Installation

On X11 (most desktops — not needed on Wayland), Qt's own xcb platform
plugin needs `libxcb-cursor0` (Qt ≥ 6.5), which a minimal install may be
missing:

```bash
sudo apt install libxcb-cursor0   # Debian, Ubuntu, Mint, ...
sudo dnf install xcb-util-cursor  # Fedora
sudo pacman -S xcb-util-cursor    # Arch
```

```bash
pipx install kortalk
kortalk --check     # diagnostics: providers, tray, PRIMARY selection
```

No other system packages or flags like `--system-site-packages` are
required for pipx/pip itself — Qt (PySide6) comes from PyPI. The only
external dependency is [Claude Code CLI](https://docs.claude.com), and
only if you use the `claude-cli` provider. `kortalk` itself checks for
`libxcb-cursor0` before starting and prints a plain error (instead of
crashing) if it's still missing.

> The config lives in `~/.config/kortalk/config.yaml` and is edited via
> Settings (or by hand). Configs of older versions (toml/ini) are not used.

## Usage

```bash
kortalk                       # start the daemon (tray + hotkeys)
kortalk --window              # dialog window (alias: --split)
kortalk --popup               # popup near the cursor (for scripts/external hotkeys)
kortalk "Translate to English:"   # popup with a one-off prompt
kortalk --provider ollama     # one-off request through a specific provider
kortalk --settings            # settings
kortalk --quit                # quit the running instance
kortalk --check               # diagnostics
```

The main scenario: `kortalk` starts the daemon, everything else is done
from the tray and via global hotkeys. The CLI flags are kept for scripting —
they are delivered to the running instance instantly over a local socket.

The popup's text is taken from the **PRIMARY selection** — selecting it
with the mouse is enough, no Ctrl+C needed.

## Hotkeys

Assigned in Settings → Prompts — the "Open window" hotkey at the top of the
tab, and one hotkey per prompt in the list below it. All of them work
globally:

- **X11** — the application grabs the keys directly (XGrabKey), works in
  any WM/DE without configuration.
- **Wayland** — the XDG Desktop Portal (GlobalShortcuts) is used;
  GNOME/KDE will show a binding confirmation dialog. If the portal is not
  available (minimalist compositors) — use the tray or bind
  `kortalk --popup` to a hotkey in your compositor.

## Provider setup

`kortalk --settings` → Providers tab. Examples:

| Provider | Type | Base URL | Model |
|---|---|---|---|
| Claude Code CLI | claude-cli | — | *(empty = CLI default)* |
| Anthropic API | anthropic | — | `claude-opus-4-8` |
| OpenAI | openai | `https://api.openai.com/v1` | `gpt-4o` |
| Ollama | openai | `http://localhost:11434/v1` | `llama3`, `qwen3`, … |
| LM Studio | openai | `http://localhost:1234/v1` | name of the loaded model |
| OpenRouter | openai | `https://openrouter.ai/api/v1` | anything from the catalog |

The dialog window picks its provider from a dropdown; the popup uses the
"active provider" by default, unless the prompt it was opened with pins
its own (Settings → Prompts). One-off CLI requests take `--provider <id>`.

## Autostart

Settings → General → "Start at login" — creates
`~/.config/autostart/kortalk.desktop` running `kortalk`.

## Development

```bash
git clone https://github.com/r4ven-me/kortalk && cd kortalk
python -m venv .venv && . .venv/bin/activate
pip install -e '.[test]' ruff
ruff check .                        # linter
QT_QPA_PLATFORM=offscreen pytest    # tests (headless)
QT_QPA_PLATFORM=offscreen kortalk --check   # headless diagnostics
```

Layout: [src/kortalk/](src/kortalk/) — `app.py` (CLI, tray, IPC),
`providers.py` (AI workers), `hotkeys.py` (XGrabKey / portal),
`windows.py` (dialog window and popup), `settings_dialog.py`, `config.py`,
`theme.py`.

Logs of the running application: `~/.local/state/kortalk/kortalk.log`
(verbose output — the `--debug` flag).

## Author

[Ivan Cherniy](https://r4ven.me) — [r4ven.me](https://r4ven.me).
Source: [github.com/r4ven-me/kortalk](https://github.com/r4ven-me/kortalk).

## Credits

The tray/window raven icon is based on the
["raven" icon](https://www.svgrepo.com/svg/156257/raven) from SVG Repo,
recoloured at runtime to match the active theme.

## License

GNU General Public License v3.0 or later (GPL-3.0-or-later), see
[LICENSE](LICENSE).
