1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# 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`. Prefer reusing the shared helpers (`select_list`, `menu`,
`field_edit`, `pad_field`, `message`, `show_error`) over new local loops.
## 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.
|