# AGENTS.md — working on bokf `bokf` is a self-hosted Swedish bookkeeping system in C11: one daemon (`bokfd`) owning a SQLite database, one JSON protocol, three clients (`bokfctl`, `bokftui`, agents). GPL-3.0-or-later. ## Build and test ```sh make -j$(nproc) # bokfd, bokfctl, bokftui make test # server/protocol test suite — must be green before you stop ``` No new dependencies without asking. SQLite, yyjson, SHA-256 and Argon2 are vendored in `vendor/` and pinned; the only system library is libncursesw. ## Layout | Path | What | |---|---| | `src/` | daemon, protocol, ledger, reports, SIE, seed, formula | | `clients/` | `bokfctl.c`, `bokftui.c`, shared `client.c` | | `docs/` | PROTOCOL.md, SCHEMA.md, COMPLIANCE.md, TUI-GUIDELINES.md | | `tests/` | in-process protocol/ledger tests (`test_core.c`) | | `data/` | BAS charts (third-party, see THIRD_PARTY_NOTICES.md) | ## Invariants — do not break these - **Protocol first.** All state changes go through commands in `PROTOCOL.md`; clients never touch the database or bypass the daemon. - **Amounts are integer öre**, dates `YYYY-MM-DD`, account numbers strings. - **Append-only ledger.** Vouchers/rows/audit are immutable; corrections are new vouchers. Never add an UPDATE/DELETE path for them. - **Everything is audited** via `audit_append`; secrets never reach the log. - **Tenant isolation**: every tenant table carries `org_id`, references are composite FKs. New tables follow the same pattern. - **Hash chains**: if you change what a voucher stores, check the canonical encodings in `SCHEMA.md` §7.1/§9.1 and `ledger.c`. ## Changing the schema Bump `BOKF_SCHEMA_VERSION` in `db.h`, add a forward migration in `db.c`, update `SCHEMA.md`, and make sure an existing test database upgrades (the test suite opens a fresh DB; migration is exercised by running the daemon on the demo DB). Never rewrite ledger rows in a migration. ## Adding a command 1. Handler in `commands.c` (or the domain file it belongs to), using the `fail()/failf()` helpers and stable error codes from `PROTOCOL.md` §5.3. 2. Entry in `g_commands[]` with permission, `need_org`, `mutating`, `dry_run`. 3. Audit (`audit_append`) for mutations, after success. 4. Update `docs/PROTOCOL.md`; add tests in `tests/test_core.c`. 5. `agent.instructions` in `commands.c` if agents need to know about it. ## Server code style C11, no comments unless the reason is non-obvious, static helpers, no VLAs. Bounded buffers with `snprintf`, check every `sqlite3_step`, free what you allocate with a clear owner. Warnings must be zero (`-Wall -Wextra …`). User-visible server messages are English; the TUI is Swedish. ## TUI work Read `docs/STATE.md` first for status, locked decisions, pending decisions and the prioritized backlog. Then read `docs/TUI-GUIDELINES.md` and follow it. Summary: one shared line editor, universal keys (Ctrl+N new, F5 refresh, Esc/q back, digits jump, `g` goto), forms behave the same everywhere, hints always visible, errors shown as `CODE: message`. Screens call only the widget layer (`clients/tui.[ch]`: `tui_menu`, `tui_select_list`, `tui_prompt_into`, `tui_edit_field`, `tui_pad_field`, `tui_message`, `show_error`) — never ncurses directly and never a local one-off loop. If no widget fits, extend the widget layer first (spec in `TUI-GUIDELINES.md` + tests in `tests/test_tui.c`). ## Verifying - Server changes: `make test`. UI changes: also drive `bokftui` over a pty (`script -qec`) or against the demo daemon and check the real behaviour. - Never run `bokftui` for tests without `scripts/tui-sandbox.sh`: it isolates `XDG_CONFIG_HOME`/`XDG_CACHE_HOME` so a run cannot overwrite the human's `~/.config/bokf/tui.conf`, `~/.cache/bokf/tui.log` or bw session. The daemon/test database must likewise live in `/tmp`, never in `~/bokf-demo` or the live NAS volume. - Never commit unless the human asks. When asked, keep the message short and in the repo's style.