The platform

The record
has doors.

A documented API, nineteen signed webhook events and an MCP server your agents can hold a conversation with — all of them running the app's own procedures. There is no second way into the database, and no door that can confirm a record on a person's behalf.

Build 0.23.0 · REST + webhooks + MCP · OIDC · SAML · SCIM · nothing hosted yet
Verification VER-0412 HV cable termination · Panel A3 · Ashwick DC Reading Verified Captured in the app · 14:31 Instrument INS-001, in calibration Hash 9f2c…a41d · day root 1 Sep Aoife Brennan PM · the second person Gland seated and torqued Confidence 0.94 Pass Phase ID sleeves fitted Confidence 0.88 Pass Screen earthed at both ends Confidence 0.41 Unclear Verified · A. Brennan · 14:32 Every door beside this one runs the same procedures. REST Idle Open GET /api/v1/verifications Your organisation header · a keyset cursor Rate limited per key · 429 with Retry-After Webhook Idle Signed verification.confirmed Signed with your secret, shown once Retries 1m · 5m · 30m · 2h · 12h, then dead MCP Idle Scoped verification_status(A3) The key sees only its issuer's own projects A posted confirm is refused · filed as a review request
One record. Three doors. No shortcuts.
19
signed webhook events, delivered with a retry ladder and a redelivery button Release 0.18.0
8
MCP tools — six read, two behind a write scope @olab/mcp · stdio or HTTP
6
connectors: Procore, Autodesk ACC, BCF, P6/Asta, QuickBooks, Aconex Release 0.18.0
19
record kinds in the search index, PDF text included Release 0.18.0
API, webhooks, MCP

Three doors, and the same lock on all of them.

The OpenAPI document is generated from the very route table the server mounts, so it cannot drift. Every write is authored by the key's owner, who has to be a member of the project they are writing to.

01 · REST

A read API you can page through

Keys are scoped by resource, hashed at rest and shown in plaintext exactly once. Keyset pagination, per-key rate limits that answer 429 with a Retry-After, X-Olab-Org on every response, an OpenAPI 3.1 document generated from the route table, and an /llms.txt for the agents that read those.

# the same route table the server mounts
GET /api/v1/verifications?limit=50&cursor=…
Authorization: Bearer olab_…

200  X-Olab-Org: northgrid
     { "data": [ … ], "next_cursor": "…" }
02 · WEBHOOKS

Nineteen events, signed and retried

Deliveries carry an HMAC signature. A failure backs off 1m → 5m → 30m → 2h → 12h and then goes dead, with a test ping and a redelivery button beside the log. The emitter swallows its own errors on purpose: a hook is never the reason a record fails to file.

03 · MCP

An agent that inherits a person's access

@olab/mcp speaks stdio for Claude Desktop and Cursor, or HTTP. An API key resolves to the colleague who issued it, so an agent sees exactly that person's projects and authors what it writes under their name. Every result carries the record ids it was built from. Two of the eight tools write, and only with a :write scope.

04 · THE LOCK

No second door into the database

Every tool and every route runs through the application's own procedures — the same membership checks, the same refusals, the same audit rows. A verification posted through the API is filed as a review request, never a confirmation: the two-party rule is not something an integration can route around.

Connectors

One adapter interface, and the conflict rule written down.

Their status wins on close; our evidence wins on content. That sentence is code, not a policy — it is the function two-way sync calls. Secrets are sealed with AES-256-GCM and never returned.

PROCORE

Punch items and observations

Snags both ways. Our evidence is rewritten beneath a fixed marker so their text survives, and a closed item keeps its status.

AUTODESK ACC

Forma / Build issues

Issues both ways. There is no priority field and no email identity over there — the adapter says so rather than faking one.

BCF 3.0

Topics in and out

Idempotent on the topic GUID, so a round trip does not multiply. The IFC viewer shows the same topics as pins, and says on the page that it does no clash detection.

P6 · MSP · ASTA

Programme in, actuals out

XER, P6 XML and MSPDI import. Actuals are written back from approved progress, never typed — the dates are derived from the records.

QUICKBOOKS

Invoices and bills

Invoices from issued pay applications, bills from confirmed receipts, with a document-number idempotency check. The interface is documented for Xero, Sage and Vista.

ACONEX

A transmittal the CDE can ingest

A zip with the register CSV in the register's own column order — no API, because Aconex seats belong to the contract's parties.

Every fixture behind these adapters is authored from the vendors' public documentation and says so on its face — none was captured from a live tenant. Connecting one needs your own credentials in that system. with your accounts

Enterprise sign-in

Your identity provider, your leaving process.

Written to the specifications rather than around them: the SAML signature is verified first, and claims are read only from the element it covers.

  • OIDC with PKCE and RS256 against the provider's published keys; SAML 2.0 over the POST binding, with every unsupported variant refused by name rather than waved through.
  • Just-in-time provisioning constrained to the domains your organisation actually claims — and it never demotes an owner.
  • SCIM 2.0 users and groups, where a group is a project role. A delete deactivates and keeps the person's name on the records they authored.
  • Sessions with a device list, revoke and revoke-all, rotated on a role change. An admin sees session counts, never a colleague's devices.
  • Enforcement refuses a password before comparing it, so an enforced domain cannot be probed.
The Security page in the current build, showing the four tabs: sign-on, provisioning, sessions and posture.

Security → four tabs · the current build on demo project data

The posture, and the control map

A control map that names its own gaps.

Every SOC 2 criterion and ISO 27001 Annex A control is mapped to the file, the function and the test that carries it — and where one is not met, the row says so. A control map that only lists what passes is a marketing document.

The region is stated, not implied

The posture card names where the data sits, whether AI is on, which model answers and where it runs, that your data never trains anything, and which fields are locked to a human judgement.

Security → Posture

The audit log leaves as a CSV

Every settings change, safety-document transition, permit act, approval and security act, with the actor and the previous value — exported over any window, and the export is itself audited.

Security → Posture → Export

One switch ends the organisation's AI

An owner turns AI off and all five callers fall back to a labelled ai-off result — no call is made, and no meter moves. The seams answer in kind rather than pretending.

Release 0.18.0

What the gaps are

Backup and recovery belong to the hosted phase and are not in this build. There is no automated destruction schedule, and no data-subject erasure workflow — because erasure fights the evidence rules and needs a stated policy first.

docs/security-controls.md

What this is not: a claim of certification. SOC 2 Type II and ISO 27001 are a purchase — an auditor, a certification body and a penetration test — and this is the software half that has to exist before any of them can start. Nobody has been hired. on request

AI operations

The only accuracy figure we publish is one you can recompute.

The dashboard is computed from your own people's decisions on the photo route — not from a benchmark, and not from us.

  • An eval harness of twenty cases and fifty-four checks authored against site photographs: defects are expected to fail, and what a frame cannot settle is expected to come back unclear.
  • Four rates over one denominator — agreement, abstention, false pass, false fail — with the false passes listed by record id so you can open them.
  • A model card whose published figures are the dashboard's own, so it moves when your build's behaviour moves.
  • Field and check locks: a locked checklist item is always judged by a person, and the AI records unclear — matched by label, so a hand-typed checklist is caught too.
  • A run that fell back to the simulated provider is filed as simulated. The label is on the record, and it survives onto the printed page.
The AI operations page in the current build, showing the dashboard tiles, the weekly series and the false-pass list.

AI ops → dashboard · model card · evals · locks — the current build on demo project data

Provenance

Exactly what it is, and exactly what it is not.

DAY ROOT

A Merkle root per organisation per day

Over the day's photos, verifications, signed forms and issued permits, timestamped through a hand-written RFC 3161 client. Any record's inclusion proof is one call, and a stamped root is immutable.

THE STUB, LABELLED

Not a qualified timestamp

With no timestamp authority configured, a local stub signs — and every surface that shows the stamp says “not a qualified timestamp” in those words. Pointing it at a real authority is a URL. on request

SIGNING

App-signed, not hardware-attested

Signing a form re-authenticates the witness within five minutes; the server signs the document hash, the signer, the time and the re-auth under an Ed25519 key. The drawn signature is decoration. Every generated PDF carries the phrase in its metadata.

ARTICLE 50

Machine-readable AI marking

The client film carries machine-readable AI-generated metadata and a manifest, and the brief names both the model and the human editor. EU AI Act transparency came into force on 2 August 2026 with a carve-out for content under human editorial responsibility — which is precisely what an approved brief is.

CAPTURE ROUTE

The photograph says where it came from

The capture route travels with the frame and is disclosed on the client's own page — “4 of 4 photos captured in-app”. Spoof heuristics (screen-of-screen, print, timing, device, position) raise a labelled warning that never blocks a confirmation, because a warning that blocks becomes a warning people learn to route around.

Deployment in Europe

The list of what it will never hold.

A German works council co-determines any device objectively capable of monitoring performance, whatever it was meant for. So the answer cannot be a policy — it has to be an absence.

  • No per-worker AI scores, ever. The analysis looks at tasks and assets.
  • No facial recognition, no biometric access, no biometric attendance.
  • No emotion or fatigue inference.
  • No continuous location of a person. Crew hours are one crew on one activity on one day.
  • No identity-linked PPE detection, no individual leaderboards, no incident-rate incentives.

The works-council pack ships with the build: a data inventory derived from the schema at call time rather than hand-kept, the never-collected list above, a per-tenant kill switch that leaves no ring, streak or recap in existence when it is off, and template works agreements in English and German.

The organisation admin console in the current build, including the data-we-hold inventory and the engagement kill switch.

Admin → “Data we hold”, generated from the schema · the current build on demo project data

Built, not deployed

All of this runs.
None of it is hosted.

The API, the webhooks, the MCP server, SSO, SCIM and the control map are written, tested and green on a local build. No region is running, no app is in a store and no auditor has been engaged — those are purchases, and they are stated as purchases everywhere on this site. Point a pilot at one package and judge the record it produces.