Metadata-Version: 2.4
Name: tyrtulia-tui
Version: 1.3.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).

The server, its API and how to run an instance are in the [Tyrtulia repository](https://git.andros.dev/andros/tyrtulia) (also on PyPI as [`tyrtulia`](https://pypi.org/project/tyrtulia/)).

- 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. Before signing, it checks that the login message names the server it is talking to, so a malicious server cannot reuse your signature on another instance.
- 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](https://git.andros.dev/andros/tyrtulia) instance, 1.x or 2.x (2.x adds login messages bound to the instance). To set one up, follow its [getting started guide for administrators](https://git.andros.dev/andros/tyrtulia#getting-started-for-administrators).

## 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`. |
| `--editor COMMAND` | Your editor for `Ctrl+O` (see [Writing in your own editor](#writing-in-your-own-editor)). Defaults to `$VISUAL`, `$EDITOR` or `vi`. |
| `--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"
editor = "nvim"            # for Ctrl+O; also "emacs -nw", "nano", "code --wait"...
# 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 |
| | `Ctrl+O` | Continue in your own editor |
| | `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.

### Writing in your own editor

You can write posts in your usual terminal editor instead of the built-in one:

1. Open the editor of the TUI as usual: `n` for a new thread, `r` to reply, `a` to answer a post or `e` to edit one. For a new thread, type the title first.
2. Press `Ctrl+O`. The TUI steps aside and your editor opens with the draft.
3. Write, save and quit (`:wq` in vim, `C-x C-s` and `C-x C-c` in Emacs, `Ctrl+O` and `Ctrl+X` in nano).
4. You are back in the TUI with the text. Check it and press `Ctrl+S` to send, or `Ctrl+O` again to keep editing.

The editor is, in this order: `--editor` on the command line, `editor` in the configuration, `$VISUAL`, `$EDITOR` and finally `vi`. Arguments are allowed:

```toml
# ~/.config/tyrtulia-tui/config.toml
editor = "nvim"
# editor = "emacs -nw"
# editor = "nano"
# editor = "hx"
# editor = "code --wait"     # graphical editors need their "wait" option
```

```sh
tyrtulia-tui --editor "emacs -nw"
```

- The draft is a temporary `.md` file only you can read, removed when you come back.
- If the editor exits with an error or cannot be found, the text in the TUI stays as it was and the reason is shown.
- The rules of the forum (lengths, too many mentions...) are checked when you send, as with the built-in editor; if the forum rejects the post, the editor opens again with your text.
- Notifications keep arriving while you write; you see them when you come back.

## 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.

## Contributing

Contributions are welcome! Please see the [contribution guidelines](https://git.andros.dev/andros/contribute) for instructions on how to submit issues or pull requests. Changes to the forum itself (the API, the server) belong in the [Tyrtulia repository](https://git.andros.dev/andros/tyrtulia).

## License

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