Access control in Truke KF is based on labels — short text tags assigned to both users and items.
A label is a plain text tag, for example staff, beta, or finance. Labels are case-sensitive.
A user holds a set of labels. An item's ACL is a list of labels, each of which can carry the operations it grants after a colon:
| Operation | Letter |
|---|---|
| Read | r |
| Write (edit) | w |
| Add children | a |
| Delete | d |
| Item ACL entry | Meaning |
|---|---|
finance | Read access for users with the finance label (the same as finance:r) |
finance:rw | Read and write access for users with the finance label |
finance:rwad | Every operation for users with the finance label |
*:r | Read access for every user |
Each operation is granted only by its own letter: finance:w lets a user edit an
item, but not read or delete it. To edit an item a user will usually need rw.
An empty ACL, on either side, means that no rules apply:
Otherwise:
* in an item's ACL stands for any user. or admin has every right, on every item. On a user,
stands for every right; on an item, for every user.Leaving a user's labels empty is a deliberate grant of every right. Users created
automatically at their first single sign-on are never left empty: they receive the
configured default labels (staff unless set otherwise).
An item's parent is the item that holds it as a component (∋), a task (*) or a
sidebar link (-). Labels follow that parent:
Items tagged reference, which are shared between several parents, are left out
of all three: they keep the labels they are given.
Setting an item's labels takes every right on it — a label carrying rwad, or
* / admin on the user. The same goes for creating an item with labels other than
the ones it would take from its parent: it takes every right on the parent. Anyone
may restrict an item that has no labels, because on such an item everyone has every
right. Without that right the field is shown but cannot be edited.
Access control is not a property of the web interface. The browser, the REST API and the MCP endpoint are checked in one place, against the same labels, so a token cannot reach anything its owner could not reach by clicking.
Two consequences are worth stating plainly, because they change what an integration sees:
An unauthorized read is answered as 404, not 403. Confirming that an item
exists but is off limits is itself a disclosure — it tells the caller there is
something there, and often what it is called. Writes answer 403, since by then the
caller has already shown they know what they are aiming at.
Lists are filtered, and their totals are counted afterwards. Search results, items by tag, relations, checklist rows and the failure-analysis walk all drop what the caller may not see, and the reported total reflects that. What you get back is what you may see, not a truncated view of what exists.
| ACL | |
|---|---|
| User Alice | staff, finance |
| User Bob | staff |
| User Carol | (none) |
| Item A | finance:rwad |
| Item B | staff |
| Item C | staff finance:rw |
| Item D | (none) |