日本語版(secondary): README.ja.adoc
officework is an Office that modernises data and drawing. It was made by Claude distilling and combining published software — Euro-Office, LibreOffice, ONLYOFFICE, Zed, Polars, openpyxl, python-docx. It does not compete on the number of features: complex work is left to AI and Python.
officework does what Microsoft Office (Word, Excel, PowerPoint and Outlook) does not do, though none of it is hard.
A Word or Excel file cannot be looked into without Microsoft Office. Taking just the data out for another tool, or changing just the look while the text stays, is not easy either. A VBA macro runs the moment the file is opened, so opening an invoice .xlsm that arrived by mail and finding a virus running is an accident that still happens today.
officework is an application that makes possible what Microsoft Office cannot do. The first thing it works on is showing Word and Excel documents exactly, on Linux. All of its code is public (AGPL). People and AI alike can read it and change it freely. Data lives in AsciiDoc text files. They can be read without Microsoft Office, and diffs work. The look is separated into a template. It can be swapped without touching the text. Macros live in .py files. Opening a document never runs them. Everything can be driven from Python, and once that is true, asking an AI to automate it is easy. This is how officework is becoming an Office that sets data, templates, Python and AI free, each on its own.
The four, in a little more detail:
-
Data — documents are AsciiDoc (
.adoc), and spreadsheets can live in the same plain-text form (.sheet.adoc). xlsx / docx are read and written as delivery formats -
Templates — the same text takes a different shape just by swapping the template
-
Python — drop a
.pyfile and call it from a cell formula like=double(A1), a ribbon button, or the macro list. Code is never stored in a workbook or a document -
AI — no AI is tied in. Anything that speaks the OpenAI-compatible API can be connected, including a model on your own machine. You can consult the AI from inside the app, and by registering the MCP server you can ask an AI to operate the running app for you
The engine also installs on its own (pip install officework): it reads and writes xlsx and docx in the idiom of openpyxl, python-docx and xlwings.
You watch the result, finish it by hand, and drive a live workbook from Python.
The app is under development.
It is not yet in a state to publish even as an alpha, and no builds are distributed. What is published and usable today is the engine (pip install officework). To try the app, build it from source (see "Building from source" below).
There are two editors: writer for documents and calc for spreadsheets. You open a folder and edit both in tabs of the same window (writer manual, calc manual).
Copilot is the only AI you can use directly inside Microsoft Office. Reaching any other model leaves two routes.
-
Write an add-in — build an Office.js add-in and call your own AI from inside it. The add-in runs in a web view inside the app, so it can do what the add-in API allows and no more
-
Hand over the whole file — let an outside tool read the document or the workbook. All of it goes to that tool
Neither is switching models on a whim.
officework lets you choose where the AI is.
Anything that speaks the OpenAI-compatible API (/v1/chat/completions) will do.
Point it at a model running on your own machine and the data never leaves it.
The destination is a setting.
Register the MCP server and you can ask an AI to operate the running app, rather than handing it a file: it works on what you have open.
Built-in enterprise AI such as Microsoft 365 Copilot answers by first searching data across the company — mail, documents, meetings, chat (the mechanism called RAG). Its safety rests on one claim: the AI respects existing access rights.
That premise is wrong. A person’s mailbox receives all kinds of information from all kinds of people. How much of it may be passed on, and to whom, is a judgment the person who knows the content makes case by case. That judgment cannot be written down in advance as machine permissions. So an AI that cross-searches the whole company on the strength of permissions will mix material people should not see into its summaries. Microsoft’s countermeasures are permission audits, sensitivity labels and monitoring — but those restate the same premise: that the judgment can be captured in settings. Internal documents cannot be handled with confidence in this shape.
officework is designed the other way around. You choose, each time, what the AI gets to see.
-
The AI sees only the folder and files you have open. No company-wide index is built
-
You choose which AI to connect. Pick a model on your own machine, and the data never leaves it
The other reason is Python in Excel. Microsoft, too, chose Python as the new way to script a spreadsheet. But that Python runs in Microsoft’s cloud, not on your machine: every time the formula computes, the cells it reads leave the machine. And VBA is still there. Defences have been added over the years — macros in files from the internet are now blocked by default — but the mechanism itself, a document that carries code, is kept for compatibility’s sake. Adding a new road while keeping the old mechanism does not make things safe. Safety needs both: code outside the document, and limits on what it may do when it runs. VBA can call anything in Windows, so as long as the existing macros must keep running, what they may do cannot be limited.
officework carries no VBA compatibility, so it could settle both at once.
-
Workbooks and documents never carry code. Nothing equivalent to VBA exists, so the "open = execute" accident cannot happen by construction
-
Python runs on your machine. Code lives outside the workbook as
.pyfiles and runs in a sandbox (it cannot reach the network or roam your files). Called from cell formulas like=double(A1)or from buttons — and the data never leaves the machine
Software developers have had a tool for keeping history (git) for nearly thirty years. Who changed what, and when — all of it recorded, any old version restorable. With Office files it barely works: they are compressed blobs whose differences cannot be read. So offices around the world still manage versions by filename — "final", "fixed", "(2)" — to this day.
officework’s documents and workbooks are plain text, so git just works. This is not a conversion like "save as CSV" — the very file you edit is what goes into history. There is no exported copy to go stale, and no formulas flattened into values. There is no encoding trap either. Windows CSV is still code page 932 with CRLF line endings — mojibake and noisy diffs the moment it meets the git world (UTF-8 and LF) — while officework files are always UTF-8 with LF (and files with stray CRLF still open). writer even saves one sentence per line, so a diff shows exactly the sentence you changed. And if you never install git, you lose nothing — plain-text files can join a history at any time, past versions and all.
The highlights only — the full list lives in the writer manual and the calc manual, which describe only what works today.
-
writer (documents) — Japanese typesetting up to vertical writing, ruby (furigana) and distributed justification. Form fields (build a form, protect it, hand it out), TOC, track changes, comments, drawing, printing where the paper changes partway, PDF. A docx can be opened, edited and saved back
-
calc (spreadsheets) — about 400 functions (incl. dynamic arrays), recalculation with circular-reference detection, multiple sheets, pivot tables, conditional formatting, data validation, charts (11 types, drawn as shapes), a solver, protection and encryption, PDF. An xlsx can too
The ribbon layout follows Euro-Office, so people who switch don’t have to relearn where things are. Commands that don’t work yet are shown grayed out — we never make something look usable when it isn’t.
There are no VBA-style macros. Workbooks (.sheet.adoc / .xlsx) hold data only, code lives in .py — separate files.
Procedures and user functions go in ~/.config/officework/plugins/; run a procedure with @name, and call a function from a cell like any other (=double(A1)).
See the calc manual.
The engine and the screen are shipped separately. Someone who only needs the engine — driving forms from Python — should not have to carry a GUI.
The engine comes from PyPI.
$ pip install officework # everything except the GUI (a 30 MB download)The current release is 0.5.0, and plenty in it is still broken. The gaps we know about are listed in the release notes. Please report what breaks at the issues.
That is enough to read and write xlsx and docx. Driving a running app from Python, and the MCP server that lets an AI do the same, are in the same package.
The screen (aiseed office) will come in the shape your machine wants — .deb, .tar.gz, .dmg, setup.exe, Flatpak. Install one and officework will start it; if the engine is already installed, the two connect as they are.
|
Note
|
On Linux, the screen needs a few system libraries — pip cannot install
those: |
Installers — not published yet. The packaging is written and produces the files below, each with Python 3.14 bundled, but no release is out:
| file | state | |
|---|---|---|
Linux |
|
built and checked here |
macOS |
|
signing and notarization are set up, not yet run end to end |
Windows |
|
installs without administrator rights. Unsigned, so SmartScreen will ask — More info → Run anyway. A Microsoft Store listing is meant to replace that |
From source — see below.
One folder holds everything you add.
It is the same path on every platform (%USERPROFILE%\.config\officework on Windows).
~/.config/officework/ ├── funcs/ Python called from cells: =double(A1) ├── ribbon/ macros that appear as ribbon buttons ├── plugins/ macros you pick from a list ├── records/ recorded actions (drafts, not run) ├── .venv/ packages you add (matplotlib, polars …) └── settings.toml language, key bindings
Open that folder in VS Code and the editor finds .venv on its own — that is why the macros and the packages share one place.
When a package is missing the app prints the exact command to install it, path and all.
Requirements: Rust (1.80+), Japanese fonts, and on Linux either Wayland or X11.
On Debian/Ubuntu the build also needs these packages (same list as CI):
sudo apt install libxkbcommon-dev libxkbcommon-x11-dev libxcb1-dev \
libxcb-xkb-dev libfontconfig1-dev cmake clang pkg-configcargo build --release
./target/release/officework # opens where you left off (asks for a folder the first time)
./target/release/officework sample/報告書.docx # bundled sample (all contents fictitious)
./target/release/officework sample/見積書.xlsx # spreadsheets open in the same appStandalone writer and calc binaries are still built for development, but only officework is distributed.
The first build takes a while because it fetches GPUI (from zed).
Not bundled. The typeface is part of the document, so we look up the font names written in the docx/xlsx among the fonts installed on this machine. If a name is missing we fall back to a font that can typeset Japanese.
OFFICE_FONT=/path/to/font.ttf ./target/release/officework # explicit overrideHaving fonts-noto-cjk or fonts-ipaexfont installed is enough.
English spelling is checked against a dictionary (/usr/share/dict/words etc.).
Japanese misconversions and inconsistent spellings can’t be caught by a dictionary, so we ask a local model.
OFFICE_HOST=127.0.0.1 OFFICE_PORT=8000 OFFICE_MODEL=... ./target/release/officeworkAnything that speaks the OpenAI-compatible /v1/chat/completions works. If it can’t connect, the app says "can’t proofread" — it never silently reports "no issues found".
There is also a standalone tool:
cargo run --release --bin office-spell -- document.txt
cargo run --release --bin office-spell -- --furigana draft.txtThe app is for shaping things while you look at them; Python is for producing data and drawings. There are buttons for charts, SmartArt, equations, pivots and the solver. Charts and pivots are done by the engine itself now — charts as shapes, pivots by Rust polars — so they work without Python installed. SmartArt, equations and the solver still call Python (matplotlib, scipy). For heavier analysis, use polars or statsmodels directly.
The engine alone is on PyPI. You do not need the apps for it.
$ pip install officeworkAn MCP server is under development too. It lets an AI assistant drive the running app:
$ pip install "officework[mcp]" # then register `officework-mcp` with your clientIt hands the AI a fixed set of spreadsheet and document tools; none of them runs arbitrary code. It talks to the app over the same mechanism Python uses, under the same rules: everything stays on this machine, and no TCP port is opened.
It embeds in other applications too.
Since 2026-08-10 the engine can stand in for the xlsx helper inside genoffice, an Electron spreadsheet, with no patch to genoffice at all — one environment variable.
Eleven of the twelve commands are officework’s, including saving; genoffice still decides what a save should change, and .xls import is the one thing not implemented.
See the engine page for the recipe and for exactly what is and is not replaced.
When you open a received xlsx or docx and write it back, the engine’s policy is to rewrite only what you changed. Parts it recognises as unreadable are listed in unsupported, as far as it can tell.
The aim is a single one: what Word or Excel shows is what comes out — in the app, on paper (PDF), and on the Web. A goal rather than a promise; the way there is measurement — real government forms rendered by officework, compared against the office’s own PDF published next to them, one discrepancy at a time.
The code below runs as pasted, against the sample/ folder of this repository.
from officework import sheet
b = sheet.Book.open("sample/見積書.xlsx")
b["見積書"]["A3"] = "株式会社みほん工業 御中" # the addressee; only the value changes
b.save("out.xlsx") # the xlsx to send on
b.save("quote.pdf") # the same content, straight to paperThe same applies to docx. python-docx rewrites the parts of a file it does not understand; this engine’s policy is to rewrite only what you changed.
from officework import doc
d = doc.Doc.open("sample/報告書.docx")
d.replace("業務", "作業") # replace; formatting inside the paragraph is left alone
d.save("report.pdf") # the edited result, straight to paperreplace() is the one to reach for when filling in a form: it keeps each run’s formatting, so a bold field label next to a plain value stays that way.
Assigning to .text replaces the whole paragraph and gives it the first run’s formatting.
A running calc can also be driven from the outside (this one needs the app running):
from officework import calc as xw # Book / Range, in the style of xlwingsThis connection is not Python-only.
The app opens a socket ($XDG_RUNTIME_DIR/officework/officework.sock): write one line of JSON, get one line back.
Anything that can write JSON can connect, whatever the language — the MCP server is just one more client of this socket.
There is no verb that runs arbitrary code.
The socket opens on Linux and macOS only; on Windows it is not created.
$ echo '{"cmd":"ping"}' | nc -q 1 -U $XDG_RUNTIME_DIR/officework/officework.sock
{"ok":true,"app":"officework","showing":"doc","version":"0.1.0-alpha"}The reference for programmers is the Python manual — ranges vs. arrays (values() and per-cell writes), 2-D lists and spilling with =PY, the d variable in writer macros, and what the sandbox allows.
All verified on a real machine.
engine/ kumihan — typesetting core (line breaking, kinsoku, glyph widths, page geometry) ooxml/ docx reading and writing sheet/ xlsx reading and writing, formula engine, styles (styles.xml) ops/ the verbs of a workbook and the sockets (open, read, write — same meaning for Python and the app) pyrun/ the machinery that runs Python (sandbox, time limits) lang/ language-specific logic; knows nothing about gpui, runs headless paper/ writes the laid-out page as PDF and PNG face/ screen parts that do no drawing (file listing, last session) ui/ glue to gpui (input, IME, ribbon) writer/ the document editor calc/ the spreadsheet editor officework/ the app itself (tabs, and the housing for the two editors) pysheet/ Python bindings (pip install officework -> officework.sheet, officework.doc) sidecar/ the separate process that rides inside genoffice
Line breaks and the position of every character are computed by one engine. The screen and the PDF both draw that same result — the design that keeps display and print from disagreeing.
The UI language switches at runtime. Built in: ja (default), en, de, es, fr, id, it, ko, pt, pt-br, ru, tr, vi, zh, zh-tw.
OFFICE_LANG=en ./target/release/officework # temporary override
# or persistently, in ~/.config/officework/settings.toml:
# language = "en"The whole UI switches — ribbon, status-bar messages, and dialogs. Every phrase is translated in every language, and a language with missing phrases is never registered.
The exact number is deliberately not written here: it only grows, so writing it down means writing something that goes stale.
The guarantee lives in cargo test instead (lang/tests/i18n_soroi.rs), which checks on every run that English has no untranslated phrase, that no dead translations remain, and that every table carries the same keys.
It used to be a script someone had to remember to run, so nobody ran it and 173 phrases went missing — a script you have to remember is not a check.
There is also a settings page: File > Advanced settings shows the current language, font, proofreading endpoint, and Python path, and cycles through the languages (the screen switches the moment you pick one).
Standard ribbon labels come from Euro-Office’s own locale files; the remaining phrases were machine-translated (by Claude, within the flat-rate subscription) following Microsoft Office terminology per language. en and ja are reviewed; review by native speakers of the other languages is very welcome.
Adding a language is one command — ui/gen_lang.py emits the material (ui/i18n/keys.json, numbered ja/en pairs), takes the translations back as ui/i18n/<locale>.json, and generates + registers the tables.
It refuses to register a language with missing or malformed phrases:
python3 ui/gen_lang.py --todo # write the material
python3 ui/gen_lang.py nl # generate + register from ui/i18n/nl.json
python3 ui/gen_lang.py --check # verify all registered languagesPer-language logic (line breaking, proofing) is contained in Language in the lang crate; implementing one trait is enough.
AGPL-3.0-or-later (LICENSE).
Origins of bundled and derived material are listed in NOTICE.md.
Ribbon buttons: nothing is grayed out — every button on both ribbons does something when pressed. When an unfinished command ships, it appears grayed rather than pretending to work.
Both figures are checked on every push against the ribbon tables themselves, so this line cannot quietly go stale — which is exactly what it had done: it said zero for months while calc showed nine.
Design decisions are recorded in SEKKEI.adoc (Japanese), history and open items in HIKITSUGI.adoc (Japanese), and there are ready-to-open samples in sample/.