GESAMT//Unitbook
Every artifact it produces carries the mark GESAMT//Unitbook <version> · <ledger head>,
naming the software and the exact ledger state the sheet was rendered from.
You trade one exchange account, and part of the money in it belongs to other people. Unitbook tracks who owns how many units of that account, prices the units every time you record the account equity, charges your performance fee by burning units instead of moving cash, and writes every step into a signed, hash-chained log. It answers one question exactly: if this investor withdrew today, how much would they get, and can they prove the number is not something you typed into a spreadsheet last night.
It runs on your laptop. There is no server, no database, no account to open, and no network call except a version check against PyPI. Your book is a folder of files. You can drive it from a chat agent over MCP, from a spreadsheet and a double click, or by typing commands. All three write the same log.
Install · Owner guide · Agent guide · Concepts · Investor verification · FAQ
Quick start
Download GESAMT-Unitbook-<version>-arm64.pkg, double click it, and a setup window opens.
It asks for your activation code, walks you through creating the book, and offers to
connect your AI agent. The installer is not signed by Apple yet, so on the very first launch
right-click the .pkg and choose Open instead of double clicking; macOS asks once.
If you would rather use Terminal, paste the one line the developer sent you. Your activation code is already in it:
curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv tool install unitbook && ~/.local/bin/uv tool update-shell && ~/.local/bin/unitbook setup ub1.xxxxxxxx
Either way you end up in unitbook setup, the whole onboarding in one word: it activates
your licence, runs the book wizard where you are standing, offers to connect your agent,
and prints what to do next. Rerun it any time; it skips what is done. The wizard asks, in
your own language, for the language, book name, currency, your name as manager (plus a
short latin code, unless your name already is one), fee percentage, high-water mark style
and timezone, confirms with a summary, then prints a 24 word recovery phrase once.
Photograph it before pressing Enter. It is the only backup of the key that signs your log.
The folder is now the book, and you never pass its path again:
book.toml book.pub events.jsonl holders.csv terms.csv
AGENTS.md journal.xlsx Unitbook.command
Full detail, including Linux and PATH, is in install.
Record the first day. A mark is the equity on the exchange before any money moved that day, so a book always starts from a mark. On a terminal every verb asks for whatever you left out and shows the diff before it writes, so you can type them bare:
unitbook mark
unitbook holders add
unitbook deposit
unitbook state
book.currency: USD
book.name: Fund
equity: 50000.00
head.id: ab3756f851ad5b8c36c9a957ae96844d8d692fd156a86a4dcc44130ddcb43cf1
head.seq: 6
holders:
id manager name status units value
farm true Farm active 0 0.00
vasya false Vasya active 50000.000000 50000.00
nav: 1
total_units: 50000.000000
version: 0.1.0
Abridged: the real body also carries the book's language and timezone, the terms in force,
any pending proposals, your licence, an update flag, first_run (true on a book never
used), and next, a short list of suggested follow-up verbs every call carries. unitbook state is the one call that shows everything; bare unitbook at a terminal is a numbered
menu of the same actions.
How it works
A book is an append-only log of typed events. Nothing is ever edited or deleted. Every number you see is recomputed by folding that log from the first event, so two people with the same log always get the same answer.
Money in buys units at the current unit price. Profit does not create units, it makes each existing unit worth more. That is the whole trick: a deposit in the middle of a profitable month cannot dilute anybody, because the depositor buys in at that day's price.
Here is a real book. Three holders on day one, at a unit price of 1.00. Written out with
flags so you can reproduce the numbers; on a terminal you would type unitbook deposit and
answer the questions.
unitbook mark --equity 0 --on 2026-09-01
unitbook deposit --holder farm --amount 20000.00 --on 2026-09-01
unitbook deposit --holder vasya --amount 50000.00 --on 2026-09-01
unitbook deposit --holder petya --amount 30000.00 --on 2026-09-01
The account is worth 100 000 and there are 100 000 units. A month later the exchange shows 112 000. Recording that mark shows what it would do before it does it:
unitbook mark --equity 112000.00 --on 2026-09-30 --dry-run
What will change:
Holder Units Value
farm 20000.000000 -> 22571.428571 20000.00 -> 25279.99
petya 30000.000000 -> 29035.714285 30000.00 -> 32519.99
vasya 50000.000000 -> 48392.857142 50000.00 -> 54199.99
Equity: 100000.00 -> 112000.00
Unit price: 1 -> 1.120000000000
A performance fee is charged: petya burns 964.285715 units.
A performance fee is charged: vasya burns 1607.142858 units.
Read it in numbers. The unit price went from 1.00 to 1.12. Vasya holds 50 000 units, so he gained 50 000 x 0.12 = 6 000, and the fee is 30 % of that, 1 800. Instead of moving 1 800 in cash, the book burns 1 800 / 1.12 = 1 607.142858 of his units and mints 1 607.142857 of them to the manager. He keeps 48 392.857142 units worth 54 199.99. Petya gained 3 600, pays 1 080, keeps 32 519.99. The manager now holds 25 279.99.
54 199.99 + 32 519.99 + 25 279.99 = 111 999.97, three cents under the equity. Units are issued down and burned up, so no holder can ever withdraw a cent more than they are entitled to; the residual stays in the pool.
Confirm, and the three events are appended, signed and chained. unitbook explain --seq 12
prints the arithmetic behind any one of them in words. See concepts.
Two ways to use it
With an agent
Register the book with every MCP host on the machine with unitbook mcp --install. It
detects Codex, Claude Code, Cursor and Claude Desktop from a shipped registry, writes one
server entry into each config it finds, leaves everything else in those files alone, and
reports one row per file saying created, updated or unchanged. --dry-run shows what
it would write; unitbook mcp --print gives you the JSON to paste into a host the registry
does not know.
The MCP server exposes one tool per verb with real argument names, and repeats the
operating rules in every tool description. init also drops AGENTS.md beside the book,
which is what a cold agent reads before its first call. The rules: never invent a mark, and
ask when the equity is unknown; mark before flow; normalise any input (text, a voice note,
a screenshot, a spreadsheet) to typed events and ask when a field is ambiguous; propose,
show the diff, and commit only after the owner confirms; never edit the book's files,
because undo is the only correction; report one line per event, being date, NAV, units
moved and value.
So the ritual is always propose, show, commit. The agent sends typed events to propose,
which prices them against the current head and writes nothing:
echo '[{"type":"mark","on":"2026-10-31","equity":"120000.00"},
{"type":"withdraw","on":"2026-10-31","holder":"farm","amount":"3000.00"}]' \
| unitbook propose --table
What will change:
Holder Units Value
farm 22571.428571 -> 21619.986903 25279.99 -> 25943.98
petya 29035.714285 -> 28455.005951 32519.99 -> 34146.00
vasya 48392.857142 -> 47425.007142 54199.99 -> 56910.00
Equity: 112000.00 -> 117000.00
Unit price: 1.120000000000 -> 1.200000000024
A performance fee is charged: petya burns 580.708334 units.
A performance fee is charged: vasya burns 967.850000 units.
That is the terminal view; piped to another program the same call answers in JSON instead.
It shows you that diff, and only then unitbook commit 2e6e2a6596e8 writes it:
committed: 13, 14, 15, 16. Commit can only ever write the events priced in that
proposal. If the log moved in between it refuses rather than repricing silently, and
proposals expire after 24 hours.
The exit code carries the meaning, so an agent never has to read prose. 0 is done. 2 is
refused, with reason from a fixed enum and hint saying what to pass instead. 3 needs
input, with questions already phrased in the book's language to relay verbatim. 4 is an
internal error, with bundle, the path to a crash report.
A refusal: {"hint": "holder 'nobody' is not an active holder", "reason": "unknown_holder", "schema_version": "1"}.
A question: {"questions": ["What was the equity on 2026-10-10, before the day's flows?"], "schema_version": "1"}.
Payload shapes, idempotency keys, dry runs and events --since are in the
agent guide.
Without an agent
No agent, no internet, no terminal typing. Two spreadsheet files with one writer each.
journal.xlsx is yours. Open it in Google Sheets, Numbers or Excel and add rows: date,
type, holder, deposit, withdrawal, withdrawal type, equity, note. The headers are in the
book's language, and Unitbook only ever reads this file.
Then double click Unitbook.command. It is a file, not an app: it sits in the book folder
right next to journal.xlsx, and you open it in Finder the same way you open anything
else. It imports the new rows, prints what they would do, waits for Enter, and commits:
Equity: 135000.00 -> 140000
Unit price: 1.384615384672 -> 1.384615384712
petya 27316.812617 -> 30927.923727
37823.27 -> 42823.27
Review the events above.
Commit to the book? Enter to confirm, Ctrl+C to cancel:
After Enter it rewrites book.xlsx (the engine's mirror of the whole book),
statements/<holder>.xlsx (one per investor, with the pin they can verify) and
export.zip. Clicking twice commits once: each row's identity is a hash of its contents,
so a re-import proposes nothing and an edited row proposes a replacement, not a duplicate.
Proof
Every event carries the hash of the previous one and an ed25519 signature over its own id. Change one byte anywhere and every event after it stops matching:
unitbook verify
findings:
code hint seq
bad_id id is e2cbd7957b257ccc0d48bbc6defcb8f4ea36a18fe415e13a805ef35440d251a4, body hashes to f2cbd7957b257ccc0d48bbc6defcb8f4ea36a18fe415e13a805ef35440d251a4 1
bad_sig does not verify against key a0482ad9ba8b0d14 1
head_seq: 9
ok: false
On an intact book, findings is empty and ok: true. verify reports every finding it
can see rather than stopping at the first, and always exits 0: a broken book is a result,
not a crash.
The signing key lives in ~/.unitbook/keys/ at mode 0600 and never enters the book folder.
unitbook keys restore --phrase "..." brings it back on a new machine from the 24 words.
unitbook keys rotate writes the new public key into the chain as an event, so old
signatures keep verifying at their own position and history is never re-signed. Losing the
phrase never loses the ledger, only the ability to append until you restore or rotate.
Every statement carries a pin: the sequence number and hash of the log head when it was
cut. An investor checks the statement against the log you sent them with
unitbook verify --seq 21 --hash 59fadeb0684fbb..., and gets the same ok: true and empty
findings. A truncated log fails the pin. A statement cut from a longer log fails it too. All of it
runs offline, on the investor's own machine, against book.pub. See
investor verification.
Files in a book
| file | written by | what it is |
|---|---|---|
events.jsonl |
Unitbook | the log. One signed, chained event per line. The book. |
book.toml |
init |
name, currency, language, decimals, genesis date, timezone, key id |
book.pub |
init |
the public key an investor verifies against |
holders.csv |
Unitbook | projection of the holder events, for reading |
terms.csv |
Unitbook | projection of the terms events, for reading |
AGENTS.md |
init |
the operating rules an agent reads before its first call |
CLAUDE.md |
mcp --install |
one line, @AGENTS.md, for hosts that do not read AGENTS.md |
journal.xlsx |
you | your input rows. Unitbook only reads it. |
Unitbook.command |
init |
double click: import, confirm, commit, render, export |
book.xlsx |
render |
the engine's mirror of the whole book |
statements/<id>.xlsx |
statement |
one investor statement, with its pin |
export.zip |
export |
the investor package and the off-box backup, in one file |
trace.jsonl |
every call | one line per call: verb, exit code, duration. No amounts, no names. |
proposals/ |
propose |
pending proposals, expiring after 24 hours |
crashes/ |
on exit 4 | crash bundles |
.lock |
every write | single writer. A second writer is refused with locked. |
Verbs
unitbook <verb> --help prints the arguments for any of these. Every mutating verb also
takes --idem <key>, where repeating a key returns the original result and writes nothing,
and --dry-run, which is identical to propose.
| verb | mutating | what it does |
|---|---|---|
setup |
yes | activate, create the book, connect the agent, all in one |
activate |
no | install a licence from a code or a file |
init |
yes | create a book in an empty directory |
state |
no | the whole picture in one call: holders, units, values, NAV, terms, head |
schema |
no | JSON schema of every verb plus the refusal-reason enum |
guide |
no | print a shipped guide: owner, agent or investor — offline copies of these docs |
events |
no | log envelopes after a seq |
explain |
no | the arithmetic behind one event, in words |
doctor |
no | check the book and its surroundings |
replay |
no | re-fold the log and rewrite the csv projections |
verify |
no | check the log, and a statement's pin, against the public key |
propose |
no | typed events in, one diff out, nothing written |
mark |
yes | record equity before the day's flows |
deposit |
yes | pay money in |
withdraw |
yes | take money out |
terms |
yes | record fee terms (terms set) |
holders |
yes | record or retire a holder (holders add, holders retire) |
commit |
yes | commit exactly the events of one proposal |
undo |
yes | reverse one event |
import |
yes | read new rows from journal.xlsx |
render |
no | write book.xlsx |
statement |
no | write a holder statement |
export |
no | write the investor package zip |
keys |
yes | show, restore or rotate the signing key |
mcp |
no | serve this book over MCP, or print or install the host config |
Output is readable text on a terminal and JSON everywhere else; --json and --table
force either. Every body carries schema_version. The same call twice produces the same
bytes, so two runs can be diffed.
Configuration
Nothing numeric lives in code. Three nouns, all data. book.toml is written once by the
wizard (name, currency, lang, money_dp, units_dp, nav_dp, genesis, tz,
signer); its immutable fields are hashed into the first event, so changing them later
breaks verification. holders.csv and terms.csv are projections: you append events and
Unitbook rewrites them, and verify reports config drift if one was edited by hand.
Terms rows are effective-dated, so a new row never reprices an earlier period:
from,holder,fee_rate,hwm,crystallise,hurdle
2026-09-03,*,0.30,every_mark,every_mark,0
hwm is every_mark or ratchet; crystallise is every_mark or on_withdraw, and a
withdrawal settles its own fee either way. Change them with unitbook terms set; monthly
is refused, so mark once a month with every_mark. The arithmetic is in
concepts, the day-to-day in the owner guide.
One book counts in exactly one currency. A deposit in another asset records asset, qty,
rate and rate_source, which the engine checks against the amount. A second currency is
a second book.
Licence, updates and reporting
Unitbook is proprietary software, licensed to named people. Your grant is a signed
license.json in ~/.unitbook/, installed by unitbook activate. Without a valid licence
every verb refuses with reason: unlicensed.
On start, at most once an hour, Unitbook asks pypi.org for the newest published version;
a successful check also renews your licence for 30 days. It never blocks the ledger, and if
PyPI is unreachable the check is skipped. If no check succeeds for 30 days the licence stops
working; upgrade with uv tool upgrade unitbook.
The software reports crashes and anonymous usage statistics (no amounts, no holder names) to the licensor. This reporting is part of the software and cannot be disabled. What goes out is listed in the FAQ.
Every statement, book.xlsx, export zip and JSON body carries the provenance mark
GESAMT//Unitbook <version> · <ledger head>. It says which software produced the sheet
and which exact ledger state it was rendered from, and it cannot be switched off.
Copyright (c) 2026 Gesamt Team. See LICENSE.
Быстрый старт
Установка на Mac, один раз, около пяти минут.
-
Скачай
GESAMT-Unitbook-<версия>-arm64.pkgи открой его. Установщик пока не подписан у Apple, поэтому в первый раз кликни по файлу правой кнопкой и выбери «Открыть»; macOS спросит один раз. Откроется окно установки. -
Оно спросит код активации, потом язык, название книги, валюту, твоё имя как управляющего (и короткий код латиницей, если имя не подходит), комиссию, тип максимума и часовой пояс, покажет сводку для проверки и предложит подключить агента. В конце покажет 24 слова ОДИН раз: сфотографируй их, потом жми Enter. Без них нельзя восстановить ключ подписи (сама книга при этом не теряется). Папку книги держи внутри Google Drive в режиме «Зеркало» (Mirror), не «Поток» (Stream). Кто предпочитает Терминал: вставь ту одну строку, которую прислал разработчик, в ней уже есть код активации.
-
В папке книги появится
journal.xlsx. Это твой журнал: Дата · Тип · Инвестор · Пополнение · Вывод · Тип вывода · Капитал на счёте · Комментарий. Правь его в Google Таблицах, Numbers или Excel, как привык. -
После новых строк: двойной клик по
Unitbook.command. Это файл в папке книги, рядом сjournal.xlsx; открывается двойным кликом в Finder. Он покажет, что запишет, ждёт Enter, и готово:book.xlsx(зеркало книги),statements/<инвестор>.xlsx(выписки),export.zip(пакет для инвесторов). Второй клик без новых строк ничего не запишет.
Через агента (Codex, Claude, Cursor): один раз unitbook mcp --install, дальше просто
говоришь «Вася внёс 500», агент сам предложит запись и попросит подтвердить.
Проверка: unitbook doctor — всё зелёное, значит порядок.
Отчёты об ошибках и статистика использования отправляются разработчику. Суммы и имена не отправляются.
Metadata
Release files for unitbook 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unitbook-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Release files / unitbook-0.1.2-py3-none-any.whl
| Download URL | unitbook-0.1.2-py3-none-any.whl |
|---|---|
| Size | 219.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad60263d5e8236a25901668252fc9b012aa17fc2edc018b30648caa1d4f60027
|
|
BLAKE2b-256 checksum How to use checksums |
9340a5828da27988cb747988d4cc26b56c813ba403e1c1a03c8ac816b8b84109
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency log