{"id":46963489,"url":"https://github.com/themoritz/turbobean","last_synced_at":"2026-03-11T10:02:54.126Z","repository":{"id":290204622,"uuid":"973521219","full_name":"themoritz/turbobean","owner":"themoritz","description":"Beancount implementation with a focus on speed and ease of use","archived":false,"fork":false,"pushed_at":"2026-02-26T22:46:16.000Z","size":1996,"stargazers_count":11,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-27T04:54:55.750Z","etag":null,"topics":["beancount","lsp-server","webinterface","zig"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/themoritz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-04-27T06:58:13.000Z","updated_at":"2026-02-26T22:46:21.000Z","dependencies_parsed_at":"2025-06-03T14:29:59.942Z","dependency_job_id":"fbaf09ba-a5e8-41de-b4ea-26a94695a0ba","html_url":"https://github.com/themoritz/turbobean","commit_stats":null,"previous_names":["themoritz/zigcount","themoritz/turbobean"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/themoritz/turbobean","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themoritz%2Fturbobean","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themoritz%2Fturbobean/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themoritz%2Fturbobean/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themoritz%2Fturbobean/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/themoritz","download_url":"https://codeload.github.com/themoritz/turbobean/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themoritz%2Fturbobean/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30377837,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T06:09:32.197Z","status":"ssl_error","status_checked_at":"2026-03-11T06:09:17.086Z","response_time":84,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["beancount","lsp-server","webinterface","zig"],"created_at":"2026-03-11T10:02:53.591Z","updated_at":"2026-03-11T10:02:54.120Z","avatar_url":"https://github.com/themoritz.png","language":"Zig","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"src/assets/img/logo.png\" alt=\"Logo\" height=100\u003e\n\u003c/p\u003e\n\u003ch2 align=\"center\"\u003eTurboBean\u003c/h2\u003e\n\nAn implementation of [Beancount](https://github.com/beancount/beancount) with\na focus on speed and ease of use.\n\n![](docs/screenshot.png)\n\nI love Beancount, but my journal is growing and the existing ecosystem with\nits Python based implementation is too slow. Also, there's no easy to set up\nLSP which prevents me from editing my .bean files in Vim. This implementation\naims to fix both.\n\nThe philosopy is:\n* you download a single small binary that doesn't have any dependencies and\n  just works\n* it contains the core Beancount logic wrapped as simple commands and\n  processing is very fast\n* provides a good LSP and formatter out of the box so all editors are supported\n* provides a simple/practical Web UI for basic needs\n* plugins are written in Lua\n* interop with other tools/languages works via templating (input) and protobuf\n  (output)\n\n## Features\n\n- [ ] Core\n  - [x] Automatic PnL Postings\n- [x] Speed (processes huge files instantly)\n- [x] LSP Server\n  - [x] Jump to account open\n  - [x] Hover account (before + after balance)\n  - [x] Auto completion (accounts, tags, links)\n  - [x] Highlight account\n  - [x] Highlight tags + links\n  - [x] Syntax highlighting via semantic tokens\n  - [x] Rename account\n  - [ ] Rename tags and links\n  - [ ] Display interpolated values inline\n- [x] Web UI (similar to [fava](https://github.com/beancount/fava))\n  - [x] File Watcher (instant reloads)\n    - [x] MacOS\n    - [ ] Windows\n    - [ ] Linux\n  - [x] Journal\n  - [x] Balance Sheet\n  - [x] Income Statement\n  - [ ] Filter language\n  - [ ] Display errors\n- [ ] Lua Plugins\n- [ ] Pretty formatter\n- [ ] Protobuf Output\n\n#### Not Planned (for now, might change my mind)\n\n- Query Language\n- Importing data (use templates in your favorite language + formatter)\n- Price fetching (same)\n\n## Installation\n\n### Download Binary\n\nGo to the [latest\nrelease](https://github.com/themoritz/turbobean/releases/latest), pick your CPU\narchitecture and operating system, then download and extract the tarball/zip to\nsomewhere on your `$PATH`.\n\n### Building from Source\n\nInstall the [Zig compiler](https://ziglang.org/). Then (assuming you have a Unix\nsystem and `~/.local/bin` is on your `$PATH`):\n\n```bash\nzig build --release=safe -Dembed-static --prefix ~/.local\n```\n\n## Use\n\n* Run `turbobean serve \u003cproject_root\u003e.bean` to launch a server that serves the\n  Web UI.\n* Navigate to `http://localhost:8080` in your browser.\n* Press the `g` key to fuzzy-navigate (e.g. balance sheet, income statement, journal).\n\n## Editor Setup\n\nAny editor that supports LSP should work. You just need to tell it to use\nthe `turbobean lsp` command to start the server (it always uses stdio for\ntransport).\n\nFor projects spanning multiple files, you can define the root .bean file as\nfollows: Create a `turbobean.config` file in the workspace folder (e.g., next\nto your `.git` folder) with the following content:\n\n```config\nroot = main.bean\n```\n\n### neovim\n\nPut this into your nvim-lspconfig's `config` function:\n\n```lua\n    local lspconfig = require 'lspconfig'\n    require('lspconfig.configs').turbobean = {\n      default_config = {\n        cmd = {\n          'bash',\n          '-c',\n          'turbobean lsp 2\u003e \u003e(tee turbobean.log \u003e\u00262)',\n        },\n        filetypes = { 'beancount', 'bean' },\n        root_dir = require('lspconfig.util').root_pattern 'turbobean.config',\n      },\n    }\n    lspconfig.turbobean.setup {}\n\n```\n\nDisable treesitter since it interferes with syntax highlighting coming from\nthe LSP's semantic tokens feature:\n\n```lua\nreturn {\n  'nvim-treesitter/nvim-treesitter',\n  opts = {\n    highlight = {\n      enable = true,\n      disable = { 'beancount' },\n    },\n  },\n}\n```\n\nMaybe there's a way we can keep treesitter enabled and then overwrite with\nthe sematic tokens info?\n\n### VSCode\n\nUse the extension in this repo:\n\n```bash\ncd vscode\nnpm i\ncode .\n```\n\nThen press `F5`, or go to debugging and click \"Run Extension\".\n\n### Emacs\n\nMinimal Emacs 30 config based on eglot:\n\n```lisp\n;; 1. Define the major mode\n(define-derived-mode beancount-mode prog-mode \"Beancount\"\n  \"Major mode for editing Beancount files.\"\n  (eglot-semtok-font-lock-init)  ; For semantic tokens\n  (eglot-ensure))   ; start Eglot automatically\n\n(add-to-list 'auto-mode-alist '(\"\\\\.bean\\\\'\" . beancount-mode))\n\n;; 2. Tell Eglot how to start your server\n(with-eval-after-load 'eglot\n  (add-to-list 'eglot-server-programs\n               '(beancount-mode . (\"~/.local/bin/turbobean\" \"lsp\"))))\n\n;; 3. Tell Eglot to use semantic tokens\n;; (from https://codeberg.org/harald/eglot-supplements/src/branch/main/eglot-semtok.el)\n(require 'eglot-semtok \"~/.emacs.d/eglot-semtok.el\")\n(with-eval-after-load 'eglot\n  ;; start eglot-semtok once we have a server connection\n  (add-hook 'eglot-connect-hook 'eglot-semtok-on-connected))\n\n```\n\n### Helix\n\nIn your `~/.config/helix/languages.toml`:\n\n```toml\n[language-server.turbobean]\ncommand = \"turbobean\"\nargs = [\"lsp\"]\n\n[[language]]\nname = \"bean\"\nscope = \"source.bean\"\ngrammar = \"beancount\"\nfile-types = [\"bean\"]\nlanguage-servers = [\"turbobean\"]\n```\n\nI don't know how to get Helix to use the semantic tokens feature so I copied\nthe existing Beancount highlight queries (from\n[https://github.com/helix-editor/helix/blob/master/runtime/queries/beancount/highlights.scm]()\nto `~/.config/helix/runtime/queries/bean/highlights.scm`).\n\n## Compatibility\n\nAims to be compatible with Beancount as much as possible, following some ideas\nfrom [Beancount Vnext:\nGoals\n\u0026 Design](https://docs.google.com/document/d/1qPdNXaz5zuDQ8M9uoZFyyFis7hA0G55BEfhWhrVBsfc/edit?tab=t.0),\nnotably [Beancount - Vnext: Booking Rules\nRedesign](https://docs.google.com/document/d/1H0UDD1cKenraIMe40PbdMgnqJdeqI6yKv0og51mXk-0/view#).\n\n#### Known Incompatibilities\n\n* The balancing algorithm doesn't automatically insert multiple postings to the\n  same account. For example, the following transaction doesn't balance:\n\n  ```beancount\n  2023-10-30 * \"Cash Distribution\"\n    Assets:Cash           -92.08 EUR\n    Assets:Cash          -794.49 USD\n    Expenses:Trips:Car    600.00 USD\n    Expenses:Food:Out\n  ```\n\n  You have to insert a second `Expenses:Food:Out` posting so that the USD and \n  EUR amounts can be put there. This is so that the editor can properly show \n  the inserted amounts inline.\n\n* How inventories work is not fully compatible to the existing Beancount\n  behavior. See [How Inventories Work in Turbobean](docs/inventories.md) for\n  details.\n\n## Developing\n\n### Prerequisites\n\n* Install the [Zig compiler](https://ziglang.org/) (project currently uses 0.15.2).\n* I recommend [ZLS](https://zigtools.org/zls/install/) as the Zig IDE.\n\n### Building\n\n```bash\nzig build\nzig build run\nzig build run -- serve foo.bean\n```\n\n### Iterating\n\nI'm using [watchexec](https://github.com/watchexec/watchexec) for automatic\nrebuilds on file change.\n\n* When iterating on Zig tests in a particular file:\n\n  ```bash\n  watchexec -e zig -- zig test src/lexer.zig --test-filter \"windows\"\n  ```\n\n* When iterating on the server (zig code or template):\n\n  ```bash\n  watchexec -r -e zig,html -- zig build run -- serve test.bean\n  ```\n\n  (page needs to be reloaded manually in the browser)\n\n* When iterating on JS or CSS files, just reload the page while the server is\n  running.\n\n### Testing\n\n```bash\nzig build test\nzig test src/date.zig\n```\n\n#### VS Code Extension\n\nPrerequisite: Install [Node](https://nodejs.org/en)\n\n```bash\ncd vscode\nnpm i\nnpm run test\n```\n\n#### Web Viewer\n\nPrerequisite: Install [Bun](https://bun.com/)\n\n```bash\ncd tests/puppeteer\nbun i\nbun test\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemoritz%2Fturbobean","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthemoritz%2Fturbobean","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemoritz%2Fturbobean/lists"}