Skip to content
engineering

How permissions work and what we refused to build

Four roles, four levels, and grants that live on folders. Plus the one feature every permission system is asked for and should not have.

Permissions are the part of a tool people only notice when they are wrong. Here is the whole model, including the parts that are missing on purpose.

Two mechanisms, not one

There are two different questions hiding inside “can they do this”, and Shaire answers them separately.

Workspace roles answer may this person use this feature at all. There are four — Owner, Admin, Member and Guest — and they govern things like editing workspace settings or managing members.

Item permissions answer may this person do that to this folder. They are per-item, and the level required varies by operation.

Keeping them apart matters because collapsing them is how you end up with twenty roles, each one a slightly different bundle of capabilities, and nobody able to say what the difference is.

The four levels

Grants are an ordered ladder rather than a bag of checkboxes:

  • Can view — show progress or reference material without risking a change.
  • Can comment — gather feedback without handing over the content.
  • Can edit — collaborate on the content itself.
  • Full control — share it, rename it, move it, delete it.

Ordered, because every check is “at least this level”. Two grants reaching the same person combine by taking the stronger one, not by union. A capability set can express states nobody wants — delete without view — and turns every question into set arithmetic.

Grants live on folders and lists

A task inherits from the list it is in. A list inherits from the folder above it. Nested folders inherit down the tree.

This is deliberately narrower than it could be. There is no per-task grant and no per-page grant, because a rule you can state in a sentence is worth more than one that is flexible, and nobody has yet asked for the flexible one.

Private folders

Marking a folder private does two things, and they are different:

  1. It stops inheritance at the folder, so the folder no longer receives what its parent had.
  2. It suppresses the default access members otherwise have — for the whole subtree, not just the folder.

The second is the one that is easy to get wrong. Applying it folder by folder would hide a folder and then hand every folder inside it straight back to the person it was hidden from.

Below a private folder the cascade resumes normally, which is why one grant on a private folder reaches everything inside it. And privacy is not a stored permission, so unsetting it restores the subtree immediately — nothing has to be repaired.

Admins can reach private folders. A folder nobody with authority can open is a folder that leaves the company with whoever created it.

Teams exist because people get hired

You can grant a folder to a team rather than to a list of people. Grant “Design” full control of the design folder, and the designer who joins in November gets it by joining the team.

Granting to five user ids instead means the sixth designer quietly cannot see it, and nobody finds out until they say so.

Invisible is a 404

If you cannot see something, asking for it directly returns “not found” rather than “forbidden”. “That exists but is not yours” confirms the id, and with it that an item by that name is in this workspace. The confirmation is the leak.

If you can see it but your level is too low, that is a 403 — pretending an item in your own sidebar does not exist would read as a bug rather than a rule.

Nothing changes if you do not use it

A workspace that has never marked anything private behaves exactly as it did before any of this existed: every member can do everything. The permission model does not switch on until you use it, and it costs nothing to ignore.

What we refused to build: deny

Every permission system gets asked for negative grants — “everyone in the team, except Sam”. It sounds small and it is the single change that makes a permission system impossible to reason about, because “why can I not see this” stops having one answer. Instead of following a chain of grants to the one that applies, you have to find every rule that might apply and work out which one wins.

So access is only ever granted, never revoked. If Sam should not have it, Sam is not in the group that does.

The other things that are not there

Being straightforward about the edges:

  • Pages carry no grants. The knowledge tree is separate from the project tree, and grants live on the project side. A guest sees no pages at all.
  • A new grant or a revoked one takes effect on the person’s next request. Making a folder private or moving it is different: that change is pushed to every open tab, so nobody has to reload to see it. Somebody removed from the workspace loses their live connection within about 25 seconds.
  • A guest’s task can reference a milestone they cannot see, and the chip renders empty. Milestones carry no grants, so there is nothing to hand over.

None of that is hidden in a footnote in the product. It is written down here for the same reason it is written down internally: the useful thing about a permission model is being able to predict what it will do.