Running a workspace

Members, roles, invitations, single sign-on, workspace settings, and what removing someone actually does.

A workspace is a tenant: its own members, its own sources, its own knowledge. Every read is fenced to it before any other rule runs, so nothing crosses between workspaces even when the same person belongs to both.

Roles gate administration, never visibility

Say it plainly, because it is the rule most people expect to work the other way: a role decides what you can administer, not what you can read. Promoting someone to admin does not widen a single answer. An owner sees exactly the claims their own source access allows, on the same terms as everyone else.

RoleCan administer
ownerEverything an admin can, plus assigning and removing ownership
adminConnections, members, invitations, single sign-on, ontology, queue retries, audit log, usage
memberNothing administrative — asks, browses, and manages their own account and API tokens

Two guards apply to ownership: only an owner may make someone else an owner, and the last remaining owner cannot be demoted or removed. A workspace with no owner is a workspace nobody can administer.

Members

Members in the sidebar (admins only) lists everyone in the workspace with their role, their principal, when they joined and when they were last seen.

  • Change a role with the dropdown in the row. An owner sees all three roles in the list; an admin can set admin or member.
  • Remove someone with the Remove button. You cannot remove yourself from this screen.

Each member has a principal that exists only inside this workspace. The same person consulting for two workspaces is two principals, which is why the wall between tenants holds structurally rather than by policy.

Invitations

Admins invite by email from Members → Invite people, choosing member or admin at invite time. Ownership is not invitable — it is held by whoever created the workspace and passed on by an existing owner.

What happens next depends on your deployment:

  • With a mail server configured, the invitation is emailed.
  • Without one, the API returns the invitation link once and the dialog shows it to you to send yourself. Anyone holding that link can join as the role you chose, so treat it as a credential.

Invitations expire (seven days by default — your operator can change the window) and appear under Pending invitations until they are accepted, revoked or expire. Revoking is immediate.

Accepting works both ways round. Someone without an account creates one and joins in a single step. Someone who already has an account joins with it, and must supply their existing password to do so — an invitation to a known address never re-keys an account.

Whether people can sign up and create new workspaces at all is a deployment setting. Some installs are invite-only, in which case joining happens through an invitation exclusively.

What the workspace is about — the vocabulary steward

Every workspace starts with all of louvain's domain templates on, so it never has to predict what it will talk about before it can remember anything. The cost is that a corpus the templates do not fit gets forced into them: a model handed feature.launch_date will file a book's 1775 publication as a feature launch, because that was the nearest slot offered.

The vocabulary steward watches for that. On a cadence — a first look once fifty events have arrived, and again only once the corpus has grown enough to say something new (at least 200 more events, or a quarter more than last time) — it reads a sample of what arrived plus the numbers (which templates captured claims, which open relations keep recurring, which entity kinds appear) and writes a profile on the Knowledge page:

  • what this workspace is about, in a sentence;
  • which templates fit and which are being forced, with a reason each;
  • predicates the open tier is already asking for, in the corpus's own words, with kinds;
  • questions the workspace could then answer well;
  • how much extraction this corpus is worth: the full ontology pass on every message, the lightweight one that writes only memories, or per message — the full pass when the text names something your vocabulary can hold, the light one otherwise. A workspace whose sources talk about things no template has a word for pays the most for the pass that returns the least; this is how it stops.

It proposes. Applying the profile switches templates (reversible, and never deletes a claim — those predicates simply stop being extracted and routed). Proposed predicates go through the ordinary suggestion list, so accepting one is the same one click, with the steward's kinds pre-filled. Autopilot, off by default, lets the steward apply its own template switches; predicates are never adopted automatically — the vocabulary grows by adoption, never by guess. Backfilling an accepted vocabulary onto what was already ingested is a re-read (POST /v1/org/extraction/rerun), as for any adoption. A re-read writes new claims; it does not remove old ones — history is never rewritten by a settings change. An operator who wants claims written under a since-disabled template, or ones the current grounding rules would refuse, taken out of every reader's view runs the grounding sweep (scripts/grounding-sweep.ts), which retracts them: they stop being served, the rows stay, and the audit log records how many and why.

On the Knowledge page the proposal is the first section, What this workspace is about: every member can read it (it names no message and quotes nothing); Apply, Dismiss and the Autopilot switch are admin controls, and Apply confirms exactly which templates it turns off and on before it does. The same verdict is marked on the Domains cards (steward: turn off / steward: turn on), and each proposed predicate appears in the suggestion list with a steward badge and its rationale. Each proposed question links into Ask. When a failure prevents the profile from loading, the page says so and offers a retry — it never shows "no proposal" for "could not tell".

Signing someone in without a password

An operator with access to the database can mint a one-time login link for any account — to open a workspace as a specific person during support, or to hand a new account its first sign-in without a password ever crossing a chat:

cd apps/api && npx tsx --env-file-if-exists=../../.env.dev scripts/login-link.ts \
  --email person@example.com [--org <slug>] [--ttl 10] [--next /app/ask]

It prints a URL once. Opening it signs the browser in and lands on the app; a second open, or one after the time-to-live (LOUVAIN_LOGIN_LINK_TTL_MINUTES, default 10 minutes), lands on the sign-in page instead. This is deliberately a script and not a button: a control that signs anyone in as anyone belongs with database access, not with a role. Both the mint and the sign-in are in the audit log, with who minted it.

Single sign-on

Under Settings → Single sign-on (admins only). There are two halves to it, and they are configured in different places.

The provider is deployment configuration

Your operator sets LOUVAIN_OIDC_ISSUER, LOUVAIN_OIDC_CLIENT_ID and LOUVAIN_OIDC_CLIENT_SECRET on the deployment. Any provider publishing an OIDC discovery document works — Okta, Entra ID, Google Workspace, Auth0, Keycloak, Clerk. No vendor SDK is involved and no identity vendor becomes a runtime dependency, which is what keeps the whole thing runnable inside your own network.

If no provider is configured, the page says so. You can still claim and verify domains; they take effect the moment a provider is wired up.

The policy is yours

Claim a domain. Enter the domain your people's email addresses use. Claiming it is not enough on its own — an unverified claim routes nobody, so that nobody can absorb another company's users by typing their domain into a box. Shared consumer mail domains cannot be claimed at all.

Verify it. The page shows a TXT record of the form louvain-verify=<token>. Publish it on the domain and press Verify now. DNS propagation takes a few minutes; "That TXT record isn't visible yet" means exactly that and is worth retrying. Once verified, the claim is exclusive to your workspace.

Set the role for new members. People arriving through SSO from a verified domain are provisioned into the workspace the first time they sign in, with the role you pick here (member or admin).

Require single sign-on. The toggle refuses password sign-in for your verified domains. Turn it on and deprovisioning someone at your identity provider actually removes them here — without it, a password is a second way in and the IdP is not decisive. The toggle is unavailable until a provider is configured and at least one domain is verified, because enforcing SSO on a workspace that routes nobody locks everyone out.

Identity is keyed on the provider's issuer and subject, not on email. Somebody changing their address at your IdP keeps the same account here rather than forking a second one. A first-time subject is only bound to an existing account when the provider asserts the email is verified.

Workspace settings

Settings → Workspace (admins only):

  • Name is editable.
  • Workspace URL (the slug) is fixed at creation. It identifies your tenant in every fenced query.
  • Your workspaces lists every workspace your account belongs to, with your role in each, and switches between them. One account, many tenants, a separate principal in each.
  • Create another workspace starts a fresh tenant with its own sources, members and knowledge graph.

Appearance

Light and dark are both first-class. The toggle in the sidebar chooses system, light or dark; the choice is stored in that browser only and applied before the first paint, so a dark preference never flashes light on load. Nothing about appearance is a workspace setting — two people in the same workspace can read the same knowledge in different themes.

Audit log

Settings → Audit log (admins only) records administrative actions in the workspace: sign-ins, invitations created and revoked, members joining, role changes, connection lifecycle, token minting and revocation, SSO policy and domain changes, workspace renames, and queue retries. Each entry carries the actor and a detail payload.

API tokens

Settings → API tokens is available to every member and is personal, not administrative. A token carries exactly the access of the person who minted it — never more — and is shown once, because only its hash is stored. Revoking is immediate.

Access insights

Access insights (admins only) is the knowledge graph auditing the permission graph: sensitive claims sitting in unusually broad rooms, material knowledge only one or two people can see, people working on something who cannot see its risks, and members who never contribute to a container they can read.

Possible duplicates

Extraction writes one node per name it resolves, and resolves narrowly on purpose: a wrong merge turns every answer about two people into a citation to the other one, while a duplicate merely lingers. So a mailbox that says "Scott" in one sentence and "Scott Waddell" in the next holds two nodes, and a question naming the short one is refused with the facts sitting on the long one.

The workspace does not settle this by itself. A miner proposes pairs it can justify and an admin decides them, on Knowledge under Possible duplicates:

  • name fits exactly one — the short name's words are all inside exactly one other name of a compatible kind, at least one of them a stated kind (two untyped words are not a thing) and at least one holding a fact, counted across the whole workspace, never over a page of nearest matches. A name that fits two or three is proposed with the others named beside it ("also fits Scott Malcolm"), scored lower, so you decide with the ambiguity in view; a name that fits more than that is a word, not a fork, and is not proposed.
  • shared connections — the two nodes share two or more distinct neighbours. Only ever corroboration on a name fit; colleagues share a manager and a company, and that alone proposes nothing.
  • a source says so — a connected account carries both an address and a display name, and the workspace holds a node for each. The source equated them, so this one confirms on its own and appears in the merged list — but only when the display name belongs to exactly ONE live node in the SAME workspace. From: Alex Smith <alex@acme.com> says that this address is that display name; it says nothing about which of the company's two Alex Smiths it is, and two connectors' "Alex Smith" are two people until something says otherwise. A namesake, or a match in another workspace, is proposed like any other pair and waits for you.

Confirming joins the two into one node by pointer: nothing is rewritten, every fact keeps its source and its room, and a single-valued predicate that both sides held is reconciled by the ordinary rule (source rank, then the claim's moment). The merged list below the candidates has an Undo for each, which replays exactly what the merge did. Rejecting a pair is remembered, and the miner never proposes it again. The highlighted name in a candidate is the one that is kept; click the other to keep that instead.

Until a pair is decided, the only thing it changes is the refusal: asking about the short name answers "No visible Role claim for Scott. Scott may be the same as Scott Waddell — unconfirmed", and nothing is answered from the candidate. That hint names only a node the asker could have been shown — like the candidate list itself, it is fenced by the reader's own containers, because a role gates administration and never visibility (ADR-005). An admin sees the pairs, the names and the volume on each side for the rooms they can read, and no others; a pair whose evidence you cannot see is not one you could judge anyway. The node the merge keeps is decided over the whole workspace, so two admins looking at the same candidate always see the same proposal. A merge changes what everyone reads about a node, never what anyone may read — entities are not principals, and a link carries no grant.

Two of the four checks — over-exposure and blind spots — key off a risk predicate in the workspace vocabulary (one whose key or label names a risk). A workspace with no such predicate enabled is told so on the page, rather than shown a clean audit: the single-point-of-knowledge and unused-access checks still run, but "nothing to flag" would otherwise mean "half the audit never ran". Enable a domain that carries one, or adopt one from the corpus's own suggestions, on Knowledge.

Insights report the shape of a claim — its predicate, its subject, and how many people can see it — never the claim text itself. A role gates administration, never visibility (ADR-005), so this audit cannot hand an admin the contents of a room they are not a member of: to read the claim behind a flag, an admin still has to have access to where it was said.

Removing someone, and what it does

Removing a member from Members takes effect immediately and does all of the following for that workspace:

  • Their membership row is deleted, so the role is gone.
  • Their readable set is emptied. No claim, observation or passage in this workspace resolves for their principal any more.
  • Their API tokens for that principal are deleted.
  • Their web sessions for this workspace are destroyed.
  • Their source identities are unlinked from the principal, so a later re-invite does not silently inherit the old readable set — it is rebuilt from whatever identities link at that point.

What does not happen: the claims they contributed stay. Attestations are history — a record of who said what, when — not a grant of permission, and deleting history to revoke access would be the wrong operation on both counts.

Their user account itself is global and survives; memberships in other workspaces are untouched. The last owner cannot be removed.

Two related revocations, for completeness:

  • Changing a password — theirs or your own — ends every session for that account everywhere, including the one doing the change. So does completing a password reset.
  • Signing out deletes the session row. Revocation is immediate rather than "whenever a token would have expired".

If your workspace enforces SSO on a verified domain, removing someone at your identity provider is the decisive action; removing them here as well is what clears their readable set and tokens.