Back up and recover a book
Every save backs up the previous file; a .log journal records changes between saves, and book.replayJournal puts them back after a crash.
red-ale protects your book the way GnuCash does, with two safety nets. Each save first copies the old file to a
timestamped backup. Between saves, every change is also written to a .log journal beside the book. If a session ends
before you save, the journal still has the changes, and you can replay them onto the last saved file.
Steps
- Save as usual with book.save. The result's
backupis the path of the copy of the previous file (book.gnucashbecomesbook.gnucash.<timestamp>.gnucash), andremovedlists old backups and journals that passed their retention.red-ale exec --retention-days 30sets how long they are kept (30 by default);--keep-backups-foreverkeeps them all. - Find the journal. book.info gives its path as
journal: a file named<book>.<timestamp>.log, written while the book is open. - After a crash, open the last saved book (not a backup, unless you mean to go back in time) and call
book.replayJournal with the journal's
path. It creates, updates or deletes each transaction by GUID.created,updatedanddeletedlist what it touched, andnotFoundlists records whose transaction was missing. - Check and save. Look at the result and at book.info, then call book.save to keep the recovered work.
- To go back to an older state, close the book and copy a backup over it, or open the backup directly. A backup is an ordinary book file.
Replay changes transactions only, not accounts. If a journal record needs an account the book no longer has, the replay
refuses that record unless you pass skipInvalid: true, which skips and lists it.
Example
Saving after a change returns the path of the backup; replaying a journal that does not exist is refused cleanly.
Example: with a copy of the reports/test-data example book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"account.create","params":{"name":"Savings","type":"BANK","parent":"Root:Asset","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":2,"method":"book.save","params":{}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"backup": "…",
"removed": [],
"compressed": false
}
}
Request:
{"jsonrpc":"2.0","id":3,"method":"book.replayJournal","params":{"path":"lost-session.log"}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": 1008,
"message": "…",
"data": {
"path": "…",
"help": "error/io-error"
}
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Savings","type":"BANK","parent":"Root:Asset","commodity":"USD"}
book.save {}
book.replayJournal {"path":"lost-session.log"}
EOF
It fails with exit status 2, printing on standard error:
{
"error": {
"code": 1008,
"message": "…",
"data": {
"path": "…",
"help": "error/io-error"
}
}
}
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Savings","type":"BANK","parent":"Root:Asset","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"book.save","arguments":{}}
Result:
{
"structuredContent": {
"backup": "…",
"removed": [],
"compressed": false
}
}
Tool call:
{"name":"book.replayJournal","arguments":{"path":"lost-session.log"}}
Result:
{
"isError": true,
"structuredContent": {
"error": {
"code": 1008,
"name": "io-error",
"message": "…",
"data": {
"path": "…",
"help": "error/io-error"
}
}
}
}