Metadata-Version: 2.4
Name: tyrtulia-tui
Version: 1.1.0
Summary: Terminal client for Tyrtulia, the headless forum for small multi-user servers
Keywords: forum,bbs,tilde,pubnix,tui,textual
Author: Andros Fenollosa
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Requires-Dist: httpx>=0.28
Requires-Dist: textual>=8.2
Requires-Python: >=3.14
Project-URL: Homepage, https://git.andros.dev/andros/tyrtulia-tui
Project-URL: Repository, https://git.andros.dev/andros/tyrtulia-tui
Description-Content-Type: text/markdown

# Tyrtulia TUI

Terminal client for [Tyrtulia](https://git.andros.dev/andros/tyrtulia), the headless forum for small multi-user servers (tildes, pubnixes, club servers). Built with [Textual](https://textual.textualize.io).

- On the server itself it talks to Tyrtulia through its Unix socket: the operating system tells the forum who you are, so there is nothing to log in to.
- From anywhere else it logs in with your SSH key (a signed challenge) and keeps the session token in a private file.
- It only knows `GET /` and follows the links the forum returns: an action appears in the footer only when the forum offers it to you (reply, edit, pin, hide...).
- Notifications arrive in real time over Server-Sent Events.

![A thread in Tyrtulia TUI](https://git.andros.dev/andros/tyrtulia-tui/raw/branch/main/docs/thread.png)

![The list of threads](https://git.andros.dev/andros/tyrtulia-tui/raw/branch/main/docs/threads.png)

## Requirements

- Python 3.14.
- OpenSSH client (`ssh-keygen`), to sign the login challenge when you connect from outside the server.
- A Tyrtulia 1.x instance.

## Installation

With [uv](https://docs.astral.sh/uv/):

```sh
uv tool install tyrtulia-tui
```

With pip:

```sh
python3.14 -m venv ~/.local/share/tyrtulia-tui
~/.local/share/tyrtulia-tui/bin/pip install tyrtulia-tui
ln -s ~/.local/share/tyrtulia-tui/bin/tyrtulia-tui ~/.local/bin/tyrtulia-tui
```

Administrators can install it once for every user of the server, for example in `/opt/tyrtulia-tui` with a link in `/usr/local/bin`.

## Usage

On the server, just run it. It finds the socket in `/run/tyrtulia/tyrtulia.sock` (or `/var/run/tyrtulia/tyrtulia.sock` on BSD):

```sh
tyrtulia-tui
```

From another machine, point it to the forum and give your username and SSH key. Your first SSH key is registered from the server itself (profile, `k`) or by the operator:

```sh
tyrtulia-tui --url https://forum.example.org --user alice --key ~/.ssh/id_ed25519
```

The key can also be the `.pub` file, to sign with `ssh-agent`. Without `--user`, you read as a guest and can log in later with `l`.

| Option | Meaning |
|---|---|
| `--socket PATH` | Unix socket of the server. |
| `--url URL` | URL of the server, for remote access. |
| `--user NAME` | Username for the SSH key login. |
| `--key FILE` | SSH private key (or its `.pub` with the agent). Defaults to `~/.ssh/id_ed25519`, `id_ecdsa` or `id_rsa`. |
| `--config FILE` | Configuration file. |

### Configuration

Every key is optional; command line options win:

```toml
# ~/.config/tyrtulia-tui/config.toml
url = "https://forum.example.org"
username = "alice"
key = "~/.ssh/id_ed25519"
# socket = "/run/tyrtulia/tyrtulia.sock"
```

Session tokens are kept in `~/.local/state/tyrtulia-tui/tokens.json` (mode `0600`), and the last post you read in each thread in `read.json` next to it, to show how many posts are new. Both follow `XDG_STATE_HOME`.

## Keys

| Where | Key | Action |
|---|---|---|
| Everywhere | `q` | Quit |
| | `i` | Notifications |
| | `/` | Search (`words`, `"a phrase"`, `OR`, `NOT`, `prefix*`) |
| | `p` | Your profile and SSH keys |
| | `l` / `o` | Log in / log out (remote access) |
| Threads | `Enter` | Open |
| | `n` | New thread |
| | `w` | Latest or watching |
| | `r` | Refresh |
| | `]` / `[` | Next / previous page |
| Thread | `↑` `↓` (`k` `j`) | Move between posts (the selected one has an orange bar) |
| | `u` | Go to the post the selected one answers |
| | `v` | Tree or linear view |
| | `r` | Reply to the thread |
| | `a` | Answer the selected post |
| | `e` / `d` | Edit / delete the selected post |
| | `s` | Subscription: watching, normal, muted |
| | `t` | Change the title |
| | `f` | Report the selected post |
| | `h`, `P`, `C` | Moderators: hide or unhide, pin, close |
| | `Esc` | Back |
| Editor | `Ctrl+S` | Send |
| | `F7` | Select all |
| | `Esc` | Cancel |
| Notifications | `Enter` | Open the post |
| | `a` | Mark all as read |
| Profile | `e` | Edit your about |
| | `k` / `x` | Add an SSH key from a `.pub` file / delete the selected key |

Only the actions the forum allows you appear in the footer.

Threads open as a tree: each answer sits indented under the post it answers, and its header shows which one (`↳ #2 bob: "First answer"`). `v` switches to the linear order, by post number, where `u` jumps back to the answered post.

## Development

Everything runs in Docker:

```sh
docker compose run --rm dev sh -c 'ruff format src tests && ruff check src tests && mypy && pytest'
```

The tests drive the client and the interface (Textual's `Pilot`) against a real Tyrtulia instance running in-process, plus a real `tyrtulia serve` with Unix users inside the container.

`e2e/run.sh` runs the end-to-end test: on Debian with systemd, ten people use the real TUI in `tmux` against one Tyrtulia instance installed from PyPI. Five Unix users go through the socket and five SSH key accounts log in over HTTP; they post, answer, mention, edit, moderate, report and search, and see each other's notifications in real time.

## License

Tyrtulia TUI is free software, released under the [GNU General Public License v3.0 or later](LICENSE).
