Warning
Pre-alpha. Not usable for real work yet. Do not use Letters, Tables or Decks as a replacement for LibreOffice, OnlyOffice, Google Docs or Microsoft Office. Documents you open may look wrong on screen, and formatting that is preserved in the saved file is often not drawn in the editor. Keep using your existing office suite, and only open copies of files you care about. See Project status.
Three GNOME-native office applications written in Rust with GTK4 and libadwaita, an email client and a Matrix chat client built alongside them, shipped as Flatpaks:
| App | What it is | Reads | Writes |
|---|---|---|---|
| Letters | Word processor | DOCX, ODT, Markdown, TXT | DOCX, ODT, Markdown, HTML, PDF, TXT |
| Tables | Spreadsheet | XLSX, XLS, ODS, CSV, TSV | XLSX, PDF |
| Decks | Presentations | PPTX, ODP | PPTX, ODP, PDF |
| Lifafa | Email client, built on Hylki; lives in tuna-os/lifafa | Mail over IMAP, POP3, JMAP, Microsoft 365, Tuta and Proton | Mail over SMTP and the same services |
| Mandelbrot | Matrix chat client with native voice and video calls, a Fractal fork; source in mandelbrot/ |
Matrix rooms, threads, polls, voice messages | The same, end-to-end encrypted |
CSV and TSV are import-only in Tables, on purpose: saving a spreadsheet
over an imported .csv would write XLSX bytes to a file everything else
reads as text, so Save As offers .xlsx instead.
Lifafa (a word for envelope) is not built from this repository. It is
Hylki by hyprlab with native Tuta and
Proton Mail accounts added, developed in the fork
tuna-os/lifafa, and it belongs to the
suite by name, icon and packaging. It is published from that repository as a
signed Flatpak repository on its GitHub Pages, and as bundles on its
releases page (see
Install). Report problems with it in
tuna-os/lifafa's issues.
Mandelbrot is built from mandelbrot/ (its own Cargo workspace and Flatpak
manifest); see docs/SUITE-INTEGRATION.md for how
the whole suite fits together.
The three apps can send the open document by email from the main menu (see docs/LIFAFA-INTEGRATION.md). Everything below this section is about Letters, Tables and Decks.
They are not a LibreOffice port. Each app has its own document model in a
GTK-free *-core crate, and compatibility with other office software is
measured against real LibreOffice output rather than asserted — see
Project status.
Your machine runs one task at a time using your signed-in AI coding CLI. The relay alternates between eligible School (OS) and Reef (apps) hives after each task. If one hive has no work, the other can continue.
The guide covers prerequisites, verified just setup, credentials, provider
costs, and how to stop with Ctrl+C. Your subscription quota or API charges apply.
Never post account credentials or API keys in issues or pull requests.
Captured automatically from the real applications by the Screenshots workflow, which drives each app under Xvfb. Nothing here is a mockup, but the demo documents were written to show features that work. Real-world files look worse (see Project status).
| Letters | Tables |
|---|---|
![]() |
![]() |
| Command palette (Ctrl+K) | Decks |
|---|---|
![]() |
![]() |
Every feature, with a screenshot of each: the feature overviews for Letters, Tables and Decks, captured the same way.
The applications are published as Flatpaks from the TunaOS repository:
flatpak remote-add --if-not-exists tuna-os \
https://tunaos.org/flatpak/tuna-os.flatpakrepo
flatpak install tuna-os org.tunaos.letters org.tunaos.tables org.tunaos.decksThen launch them from your application menu, or:
flatpak run org.tunaos.lettersLifafa is not in the TunaOS repository; it has a signed Flatpak repository of
its own (coming with its first release published there, v1.47.1-tuna6), which
flatpak update follows:
flatpak install --user https://tuna-os.github.io/lifafa/org.tunaos.lifafa.flatpakrefUntil then, or to install a file, download the bundle from the
latest release of tuna-os/lifafa
and install it with flatpak install --user org.tunaos.lifafa-<version>.flatpak.
The signing key, the bundles and moving an older bundle install over to the
repository are in
Lifafa's install instructions.
Something not working? See docs/USER-TROUBLESHOOTING.md.
Flathub submission is prepared but not yet submitted — the remaining steps need a human and are written down in flathub/README.md.
Current release: the latest on GitHub — its version number is not a maturity claim.
Honest status: pre-alpha, not a daily driver. The file-format engines (reading and writing DOCX/ODT/XLSX/ODS/PPTX/ODP) are the most mature part and are tested against LibreOffice. The editors, meaning what you see on screen while you work, are catching up, and are now measured:
- On-screen rendering is compared with LibreOffice's, feature by feature. The render lab draws one fixture per feature in our apps (headless, and in a browser via GTK Broadway) and in LibreOffice, and compares the two. The current results and accepted metric artifacts are in the generated table below.
- Real-world documents and the installed Flatpak are measured too. The real-document corpus (#1200) and Tier C on a GNOME VM (#1199) expose gaps single-feature fixtures cannot. Until both are green for an app, it is not "usable for everyday documents", whatever its single features score.
- The README screenshots come from demo documents chosen to show what works. They do not represent arbitrary real-world files.
| App | Single-feature fixtures, Tiers A and B | Real documents | Shipped Flatpak (Tier C) | Status |
|---|---|---|---|---|
| Letters | 42 / 48 green + letters/table (accepted amber); not green: letters/bullet-symbol-font-line-height, letters/floating-image-gap, letters/odt-page-break-spacing, letters/table-cell-numbered-list-indent, letters/table-row-min-height-page-break |
19 / 30 green | 37 / 78 green | Not yet usable for everyday documents |
| Tables | 22 / 43 green; not green: tables/filtered, tables/fit-to-width, tables/horizontal-pagination, tables/hyperlink-theme-colors, tables/oversized-unheaded-instructions, tables/paginated-columns, tables/print-scale, tables/tall-unheaded-postcodes, tables/tall-unprinted-sheet, tables/unheaded-bordered-musts, tables/wide-borderless-hyperlinks, tables/wide-column-no-headings, tables/wide-column-right-align, tables/wide-unheaded-complaint-log, tables/wide-unheaded-consumption-estimates, tables/wide-unheaded-contact-list, tables/wide-unheaded-deep-sea-stock, tables/wide-unheaded-transactions, tables/worksheet-image, tables/wrap-merged, tables/wrap-wide-default-font |
2 / 30 green | 16 / 73 green | Not yet usable for everyday documents |
| Decks | 17 / 18 green; not green: decks/pay-centre-reduced-line-breaks |
1 / 30 green | 15 / 48 green | Not yet usable for everyday documents |
This table is generated by tools/render-lab/readme_status.py from the
render-lab scorecard (single-feature baseline
and real-document baseline); CI fails
when the table disagrees. Non-green real documents are tracked by
render-real issues.
A release also needs a green Tier C run on the release candidate and a
documented gap list; see the Phase 4 exit.
Measured file compatibility (file content, not on-screen rendering). Four corpora are ratcheted in CI. The pass count may climb but never fall:
| Corpus | Score | What it checks |
|---|---|---|
| CommonMark 0.31.2 | 652 / 652 | Every spec example round-trips idempotently through Letters' model |
| LibreOffice ↔ Letters | 109 / 109 | Documents survive a real LibreOffice Writer pass |
| LibreOffice ↔ Decks | 9 / 9 | Decks survive a real LibreOffice Impress pass |
| OpenFormula | 107 / 107 | Formula evaluation against the ODF spec's own cases |
These use LibreOffice itself as an oracle, not a hand-written expectation of what it would do. A missing oracle is a failure in the required lanes, never "observed compatibility". Feature-by-feature detail is in docs/PARITY.md.
Current focus: crashes and flakiness, not features. The work in docs/readiness-2026-09/ is a September readiness push. The honest summary is that it keeps finding real defects — seeded command-sequence campaigns run nightly against all three document models, recorded GUI journeys run on every pull request, and every package reader is bounded against hostile input. Each of those landed because the instrument found something, and each readiness document marks what is not done rather than rounding up.
Where this is going next: ROADMAP.md.
You need Rust and the GTK4 + libadwaita development libraries (gtk4-rs 0.11, libadwaita 0.9, targeting the GNOME 50 runtime).
cargo check --workspace # fast — no linking
cargo run -p letters # or -p tables, -p decks
cargo test --workspaceA justfile wraps the common loops:
just setup # create the toolbox container with the build dependencies
just preflight # check + lint + test, the same gates CI runs
just test-gui-all # the AT-SPI GUI journeys, inside the toolboxA flake gets you running without installing GTK development libraries yourself:
nix run . # Letters
nix run . -- tables # letters | tables | decks
nix develop # dev shell with Rust + GTK4/libadwaita
nix build # all three apps plus desktop/schema/icon filesnix develop points GSETTINGS_SCHEMA_DIR at flatpak/, so
cargo run -p letters works immediately.
Two crates (IronCalc, rdocx) are pinned to git revisions and fetched with
allowBuiltinFetchGit, so no dependency hashes need maintaining.
flake.lock is not committed — run nix flake lock on a Nix machine
to pin nixpkgs and commit the result.
flatpak run org.flatpak.Builder --state-dir=.flatpak-builder \
build-dir flatpak/org.tunaos.letters.jsonEvery app is split in two: a *-core crate with no GTK dependency
holding the document model and file formats, and a thin GTK binary on top.
That split is what makes the document models testable without a display,
and it is where most of the test suite lives.
| Crate | GTK? | What lives there |
|---|---|---|
letters-core, tables-core, decks-core |
no | Document models, file readers and writers, undo commands |
letters, tables, decks |
yes | Windows, widgets, Cairo rendering, actions |
suite-common-core |
no | Shared primitives: undo, number formats, styles, search, atomic saves, autosave |
suite-common |
yes | Shared widgets: command palette, file dialogs, toasts |
suite-export |
no | PDF export |
suite-collab |
no | The wire protocol between an app and the collabd sidecar (serde only, no network stack); off by default, see collab/ and RFC-0005 |
Other directories: tests/ (GUI journeys and Python harness tests),
interop/ (the reviewable interoperability corpus), fuzz/ (cargo-fuzz
targets), flatpak/ and flathub/ (packaging), collab/ (the collabd
collaboration sidecar, its own cargo workspace and lockfile so no network
crate reaches the apps), docs/, po/ (translations).
For module layout, data flow, the LibreOffice patterns this borrows from, and the dependency inventory, see docs/ARCHITECTURE.md.
Tests are layered, and the layers answer different questions:
| Layer | Command | Question it answers |
|---|---|---|
| Unit and model | cargo test --workspace |
Does the document model do the right thing? |
| Property and round-trip | part of the above | Does write → read return what went in? |
| LibreOffice oracle | REQUIRE_SOFFICE=1 cargo test |
Does other software agree? |
| Stateful campaigns | cargo test -- --ignored seed_campaign |
Does a long random command sequence break an invariant? |
| GUI journeys | just test-gui-all |
Does the application actually do it, on a real display? |
The GUI journeys drive the real applications through AT-SPI under Xvfb in a
container, and can record what they did: add the verify-video label to a
pull request and the recorded clips are written into its description. See
docs/GUI-TESTING-SPEC.md and
docs/CI-VIDEO-EVIDENCE.md.
The oracle suites need LibreOffice Writer and Impress installed; without them they fail rather than silently skip, so a green run means the oracle really ran.
Start with docs/CONTRIBUTING.md — it covers the Rust/GTK patterns this codebase uses, commit style, module size limits and the pre-commit gates. AGENTS.md is the instruction set for automated contributors.
Good first things to look at:
- Open issues labelled for the current readiness push in docs/readiness-2026-09/ — each document lists what is still open, with reproductions.
docs/PARITY.mdrows that are not yet green.
File bug reports and feature requests in this repository. If you are coming from the deprecated Python applications, see the deprecation and migration roadmap.
| Document | What it covers |
|---|---|
| docs/ARCHITECTURE.md | Workspace layout, module structure, data flow, dependencies |
| docs/CONTRIBUTING.md | Conventions, workflow, pitfalls |
| docs/DEVELOPMENT.md | Environment setup |
| docs/GNOME-GUIDELINES.md | HIG compliance rules and widget patterns |
| docs/OVERVIEW-VIDEOS.md | The GNOME-styled overview videos: how they are recorded and kept current |
| docs/USER-TROUBLESHOOTING.md | Common setup, build, test and runtime problems |
| docs/ACCESSIBILITY.md | Keyboard shortcuts, keyboard-only use, and screen-reader support |
| docs/PARITY.md | Feature-by-feature compatibility truth table |
| docs/TESTING.md | Test strategy (docs/TEST-PLAN.md is the v1.0 plan, kept as history) |
| docs/GUI-TESTING-SPEC.md | The AT-SPI journey harness |
| docs/CI-QUALITY-GATES.md | What CI enforces and why |
| docs/readiness-2026-09/ | Current readiness work, item by item |
| docs/RELEASE.md | Release process |
| docs/adr/ | Architecture decision records |
| CHANGELOG.md | What changed when |
GPL-3.0-or-later, with one directory under another licence:
lifafa/(the email client, from Hylki) is AGPL-3.0-or-later; its ownlifafa/LICENSEapplies there.mandelbrot/(the Matrix client, from Fractal) is GPL-3.0-or-later, the same as the rest.
AGPLv3 and GPLv3 each allow the two to be combined in one work (section 13 of
each), so a distribution of the whole suite is covered by both: the AGPL's
network-use clause applies to the AGPL part. Details and origins are in
THIRD-PARTY-NOTICES.md. All source files carry SPDX
headers. The GTK-free core crates published on crates.io (suite-common-core,
suite-export, tables-core) are under the same license as the rest of the
office apps.



