Security & governance

What the platform does, stated plainly

This page describes mechanisms that exist in the product. It makes no certification or compliance claims, because we hold none — where that matters to you, ask and we will answer precisely.

Access

Authentication and sessions

Passwords
Hashed with bcrypt. Plaintext is never stored, and a login for an unknown address performs the same work as one for a known address so the two cannot be told apart by timing.
Sessions
A signed, httpOnly, SameSite cookie. No token is placed in localStorage.
Revocation
Each account carries a token version; changing a password or signing out everywhere increments it and every existing session stops being accepted.
Reset
Single-use links, stored only as a hash, expiring in 30 minutes. Requesting one answers identically whether or not the address is registered.
Rate limiting
Per user or client address. Credential endpoints fail closed if the limiter itself is unavailable, so an outage cannot remove the only brake on guessing.
Client address
Taken from the entry the nearest trusted proxy wrote, not the one the caller claimed.
Invitations
The only route into an organisation for an outsider. Tokens are stored as hashes and shown once.
Suspension
A suspended or archived account cannot hold a session, checked on the same read as the token version.
Isolation

Tenancy is structural, not conventional

Every project, document, chat, run and usage row belongs to exactly one workspace inside one organisation. Authorisation resolves from membership and role — never from who created a row.

The vector store is the one denormalised table, and it carries organisation and workspace on every chunk; the similarity search filters on them in the query. The retrieval function requires a workspace argument, so a caller who omits it fails to compile.

A resource in another workspace answers 404, not 403: a 403 would confirm that the id exists.

Organisation
The billing and identity boundary. People join it once.
Workspace
The data boundary. Every project, document and run belongs to exactly one.
Project
One engagement: its brief, its knowledge, its deliverables.
Deliverable
A document with its own version history.

Access is membership, never row ownership: a colleague in the same workspace reaches its projects, and a resource in another workspace answers 404 rather than 403 — a 403 would confirm it exists.

Authorisation

One capability matrix, checked everywhere

Roles do not grant access by name anywhere in the codebase. Every guard asks for a capability, and the role-to-capability mapping is defined once.

Single gate

Project-scoped requests pass through one function that resolves the workspace, unions the caller's roles and requires the capability the operation needs.

Derived lists

Where a service needs a list of roles, it is derived from the matrix rather than hand-written beside it.

Custom roles

An organisation can define its own, but only from capabilities the author holds, and never including organisation ownership or deletion.

Record keeping

Audit and activity

Two different things: an append-only audit of privileged and state-changing actions, and a readable activity feed built from it.

What is recorded
The action, the actor, the organisation and workspace, the target, and the request's address and agent.
What is not
Values. The log records field names only — requirements, deliverable content, chat messages, billing addresses and spending limits stay out of it.
Retention
Append-only. Deleting a user or organisation nulls the reference rather than erasing the history.

Exports are audited specifically, because an export is the moment client-confidential material leaves the system: what was exported, in which format, how large — never the content.

Generation is recorded the same way. Every run leaves provider, model, tokens, duration and cost against the project and workspace it belongs to.

AI providers

Keys, models and what leaves the deployment

Keys are never returned

No endpoint returns a provider key. Only its presence is reported, and masking happens on the server.

Your own providers

Providers are configured per deployment; the model is chosen per run. Enterprise deployments use their own keys entirely.

What is sent

A generation sends the brief, the retrieved passages, the dependency documents and the instruction to the provider you selected. Nothing else leaves.

No training on your material

Uploaded documents are extracted, embedded and stored inside their own workspace, and used only to ground that workspace's generations.

Spend

Controls that refuse rather than warn

A ceiling is only a control if something stops when it is reached.

Where it is checked
Before a pack run starts, before every document inside that run, before a single generation, and before a chat turn.
What happens
Generation is refused for every workspace in the organisation until the month rolls over or the limit is raised.
How cost is computed
From rates configured per provider and model, applied to the tokens each call actually used.
Unpriced models
Work on a model with no configured rate is reported as unpriced rather than counted as free, because a ceiling cannot see spend it never valued.
Honest limits

What we do not claim

A security page that only lists strengths is not a security page.

No certifications

We hold no SOC 2, ISO 27001 or equivalent attestation today, and will not imply otherwise.

Deployment-dependent

Encryption at rest, network policy and backup regime are properties of where you run it. Self-hosting puts those decisions with you.

Prompt injection

Uploaded material is delimited and budgeted, but a document that contains instructions is a known risk in every retrieval system, ours included.

Send us the security questionnaire

We would rather answer a specific question about a mechanism than publish a badge. Ask, and you will get the mechanism.