Skip to content

Controlling What Each Person Sees

Access rules decide which labels get stamped on each document when it is indexed. An actor sees a document when they hold one of its labels. That is the whole model.

Two pages are involved, and it is worth knowing which does what:

  • Directory (/app/directory) — the Folder access rules section, below the actors and groups tables, is where rules are written. It sits there because rules reference the actor and group ids defined directly above them.
  • Access (/app/access) — where you check the result: run health checks and ask what a specific actor would see. It writes nothing.

Rules also reference workspace ids from Workspaces.

Labels are stamped at ingest

Changing a rule does not change documents you already indexed — they keep the labels they were stamped with. After changing rules, re-stamp the existing documents (there is a button for it) and then apply a reload. New ingests use the current rules automatically.

Turn it on

Two switches at the top of the Folder access rules section on Directory, and both matter:

  • Access control enabled. With it off, every request to your tenant sees all of your data unfiltered and the labels below stop applying.

  • Require an actor on every request. With it off, a request that asserts no actor also runs unfiltered. Turn it on to reject any request that does not identify a user.

    Your operator can force this on for the whole deployment. When they have, this toggle still reads off here — it is your tenant's own setting, and the effective answer is the two combined. So a request can be rejected for asserting no actor while this page shows the gate as off. Access reports it as a finding when that is the case, and Connect MCP renders the x-ugent-actor header into its examples on the strength of the effective value rather than this one.

A tenant serving one trusted application can reasonably leave access control off. A tenant serving several people cannot.

Choose a layout

Each workspace entry picks a layout, which is a shorthand for the common folder conventions so you do not have to write a rule per folder.

  • group_actor<Group>/<Shared folder>/** is visible to the whole group (label group:<group>), and <Group>/<Actor>/** is private to that actor. The shared folder name is configurable and defaults to Shared.
  • none — no convention. Only your explicit prefix rules and the default labels apply.

Prefix rules

Prefix rules are checked before the layout, and the first match wins. Each rule is a path prefix plus the labels to stamp on anything under it.

The prefix is matched against the path from the workspace root, and it is case-sensitive. It is a literal match unless it contains a wildcard: * within one segment, ** across segments, ?, or [...].

End a prefix with / and it covers that folder's whole subtree. Without the slash, a literal ugent also matches ugent-analytics/ — which is usually not what you meant.

One glob rule can replace many literals: ugent-*/ covers every ugent-* channel folder.

Labels

LabelGrants
group:<id>Everyone in that group. The one to reach for by default.
actor:<id>One specific person.
group_admin:<id>The group's supervisors — who also read that group's members' private folders.
publicEveryone, because every actor holds it.

Use the Insert label picker rather than typing ids. It lists your real groups and actors and inserts the id folded exactly the way the engine stamps it, which removes a whole class of "the rule looks right but matches nothing" bugs.

Default labels

Whatever no rule and no layout matched gets the default labels for that workspace.

Leaving this empty falls back to public, which every actor holds. So to keep unmatched paths private, do not clear the field — name a label only your own group has. An empty default is the most common way to accidentally share everything.

Workspace ids and globs

Each entry names one workspace id, or a glob covering several. Exact ids take priority over globs.

A real workspace id is the folder name plus a hash assigned at first ingest, for example ugent-web-c72bda4d1e49; the Pick a workspace dropdown lists the ones you own. Use a glob such as ugent-* to cover a workspace before you know its hash — it matches every current and future ugent-* workspace.

Save, re-stamp, reload

The order matters, and the console nudges you through it:

  1. Save access config. Stored, not live. The Dry run button starts highlighting to tell you a change is waiting.
  2. Re-stamp existing documents, if you changed rules and already have content indexed. This applies the saved rules to what is already there. Nothing else can do it — a document's labels are decided at ingest.
  3. Dry run, then Apply reload. Now the rules are in force.

Verify before you trust it

Two read-only tools on the Access page, and it is worth using both:

  • Setup check runs health checks and reports what is wrong with stable codes — a workspace with no access rule, a connection whose scope was never granted, a source that never synced.
  • What would this actor see? resolves one actor's labels and explains them, without holding their key or impersonating them.

Both compute from configuration alone and read no indexed content.

How filtering is enforced

Worth knowing so you can reason about the guarantees rather than hoping:

  • The acting actor is resolved server-side from the key or header. It is never taken from tool arguments, so a client cannot claim to be someone else.
  • Access conditions are added on top of tenant isolation, never replacing it. A rule mistake can over-share within your tenant; it cannot reach another tenant.
  • Every retrieval path is filtered: vector results, lexical matches, graph traversal, and memory recall. Graph nodes an actor cannot see are dropped before the response is built.
  • Unknown and disabled actors are rejected outright.

Released under the Private Beta License.