Security
What we have done about security, and what we have not.
38 questions an enterprise review asks, with our real answer to each — 17 in place, 13 partial, 0 in progress, 7 not done; 1 does not apply. It is the same page your security lead reads inside the app, where seven of the answers are measured against the live database rather than asserted. No certification is claimed on this page, because none is held.
macOS app, Windows next · free for ten interviews a month, no card
Your reviewer gets a seat that sees no candidates.
A Security role — narrower than an admin, on purpose. It reads everything about how the product is controlled and nothing about the people it is used on. An auditor who can change what they audit is not an auditor, and “our security lead has read-only access to controls and cannot see candidate data” is a sentence worth being able to say out loud.
- Can see
- Who holds which role. Every integration, its scopes, who connected it. Every control on this page and its live state. The audit log. Which AI provider processes what.
- Cannot see
- Candidate names, emails or files. Transcripts, deliverables, scorecards, verdicts. Interview content of any kind.

- How is authorization enforced?
- in placemeasured live in the app
One permission model. Permissions are named for what they protect rather than who holds them, and every check asks can(role, permission). An unknown role holds nothing, so a typo fails closed.
- Can somebody reviewing your security see candidate data?
- in place
No. The Security role reads every control, integration and audit entry, and no candidate, transcript, deliverable or scorecard. An auditor who can change what they audit is not an auditor.
- Can any employee of yours view a customer's data?
- in place
Only an account owner can view their own organization through another member's eyes, and only within that organization. It cannot be used to climb, and the real identity is carried alongside: every audit event and configuration snapshot names the owner as the actor and records the seat they were viewing from. Deploy Ready staff have no such route into a customer account.
Every action is written down, and nothing can rewrite it.
The audit log is written from inside the action that caused an event, never by a client saying one happened; nothing updates or deletes a row; a refused attempt is recorded as denied; and reading the log is itself logged. Anything that looks like a credential — by its field name or by its shape — is redacted before it is written. Under view-as, the person recorded is the owner, with the seat they were in beside them.

- Do you keep an audit log, and can it be tampered with?
- in placemeasured live in the app
Yes, and there is no write path from a client — events are recorded from inside the action that caused them. Nothing updates or deletes a row. Reading the log is itself an audited event, and a refused read is recorded as denied. A reader who holds audit.read without the candidate grant — the Security seat — sees the log with the people redacted: an actor who is not a member of the organization is shown as "a candidate", the label of an object that names a person is withheld, and each event's meta is reduced to an allowlist of keys that carry counts and the names of things.
- Could a secret end up in your logs?
- partial
Redaction happens in the audit helper rather than at each call site, catching credentials both by field name and by the shape of the value, at any depth. Application logs are less rigorous and are the weaker half of this answer.
To close it: A structured logger with the same redaction applied to application logs.
One customer’s data never answers another’s query.
Every table that holds a customer’s data carries their organisation, and every read scopes to it inside the query rather than filtering the result afterwards. A check that runs on every push fails the build if a route reads a whole table. That is the mechanism. What is not in place is the database enforcing the same rule underneath — row-level security is off, and the register says so.
- How do you keep one customer's data away from another's?
- in placemeasured live in the app
Every tenant-owned table carries an org_id, and every read scopes to it in the query rather than filtering afterwards. A static check in CI fails the build if any route reads a whole tenant table.
- Do you test for cross-tenant access?
- in place
Yes, two ways: a static check over every API route that runs on each push, and a live-data assertion that every tenant row is attributed. The static one found a real leak that code review had missed three times.
- Is isolation enforced at the database as well as the application?
- in placemeasured live in the app
Yes. Every statement runs as its organization -- a transaction-local setting the database reads -- and every tenant table carries a policy that returns no rows when that setting is absent and refuses a write that would land in another organization. The application connects as a role without BYPASSRLS, so the database, not just the code, is what refuses. The measurement below is the live state, role included.
Credentials are sealed before they reach the database.
Calendar tokens and ATS keys are encrypted with AES-256-GCM — a fresh nonce for every value and a tag that makes tampering detectable — before they are stored, with the key held in the platform’s secret store and never in the application or in source. The database is encrypted at rest by the provider too, which protects the disk and not the row; that is why credentials are sealed separately. What is not yet sealed the same way: transcripts, deliverables and datasets.
- Are credentials and interview content encrypted at rest?
- in placemeasured live in the app
Yes. OAuth access and refresh tokens and ATS API keys (Greenhouse, Ashby, Lever, SmartRecruiters, Workable) are sealed with AES-256-GCM before they reach the database, with a per-value IV and an authentication tag. The key comes from the platform's secret store, never from the application. An ATS key stored before sealing existed is re-sealed the next time it is read. Since 7 Sep interview content is sealed the same way before it reaches the database: transcripts, timelines and notes, the files a candidate produced, dataset bodies, and the drafted summaries and assessments (lib/content.ts); every existing row was sealed by a backfill the same day; a write without the key is refused rather than stored in the clear. Scorecard notes and message bodies are not yet sealed.
- Is the database encrypted at rest?
- in place
Yes, by the managed provider. Worth noting this protects the disk, not the row — which is why credentials are separately sealed above.
- Where do encryption keys live?
- in place
In the deployment platform's encrypted environment store, and in a local .env for development. Never in source control — a key the application can mint would end up in the same backup as the data it protects.
- Is data encrypted in transit?
- in place
Yes. All API traffic is HTTPS, and the interview room's media and data channels are WebRTC with DTLS-SRTP.
Candidate code runs on the candidate’s machine.
Not on ours, and not on the interviewer’s. We are not a sandbox and do not claim to be one; the boundary is that their machine is neither of the other two. The desktop app is hardened to protect the person running it, and the register lists both what is done and what is not.
- Candidate code runs somewhere. Where, and how is it contained?
- in place
On the candidate's own machine, in their own shell, as them. We are not a sandbox and do not claim to be one — the boundary is that their machine is neither ours nor the interviewer's. Nothing a candidate writes executes on our infrastructure.
- It is an Electron app. How is it hardened?
- partial
Context isolation is on and node integration is off in the renderer, which is one local document that may not navigate anywhere else; new windows are refused and links open in the person's own browser. A Content Security Policy forbids inline and remote script. Pages may ask the OS only for the camera, microphone, screen, fullscreen and clipboard write. The preview's embedded page gets no preload and no Node, is sandboxed, and may only point at this machine. File access over IPC — the tree, reads, writes, the profile read-back and the workspace snapshot — is confined to the workspaces the main process itself opened, resolved through symlinks so a link committed into a repository cannot point out of it; repository status, change-watching and reveal-in-Finder still take a renderer-supplied root and leak only metadata. The candidate's shell starts from an allowlisted environment rather than the app's own. The renderer itself does not yet run under Electron's sandbox, and IPC payloads are checked by the handlers that take paths rather than validated as a whole.
To close it: Electron's `sandbox` on the renderer, and schema validation on every IPC payload rather than only on the handlers that take paths.
- Do you record interviews?
- does not apply
No. There is no video or audio recording, by choice. A transcript is produced from speech on each participant's own machine, and the code the candidate wrote is stored as a deliverable.
- What monitoring runs on a candidate's machine?
- in place
Only with their explicit consent, shown as a full list before anything runs, and declining is recorded rather than penalised. It never reads their screen, keystrokes, files or other applications, and cannot prevent anything from running. We can detect, with permission; we cannot enforce, and do not claim to.
Signing in, and who can see what.
GitHub, or a single-use email link that expires in fifteen minutes; there are no passwords, so there is no password store to breach. Sessions are server-side rows, ended when the person signs out. Single sign-on and a second factor on the email door are not built.
- How do users authenticate?
- in place
GitHub OAuth, or a single-use email link that expires in fifteen minutes. There are no passwords, so there is no password store to breach or policy to enforce.
- How are sessions handled and revoked?
- partial
Sessions are server-side rows with an expiry, checked on every request. Signing out (POST /api/auth/signout) deletes the row the cookie names and clears the cookie, so a session ends when the person ends it rather than when the clock does. There is no per-device session list yet, so a session on a machine you no longer hold cannot be ended from another one.
To close it: Visible device and session list, with revoke.
- Do you support multi-factor authentication?
- partial
Not directly. Where sign-in is through GitHub, that account's MFA applies. The email link path has no second factor of its own.
To close it: MFA on the email path, and an organization setting to require it.
- Do you support SAML or OIDC single sign-on, and SCIM provisioning?
- not done
Not yet. The identity model is email-or-OAuth with a session table, which is compatible with adding them — no password store would have to be unwound first.
To close it: A SAML/OIDC provider per organization, and SCIM for provisioning and deprovisioning.
Where your data goes when someone uses the assistant.
An agent already on the machine runs there, and nothing about your pipeline is relayed to us. When the assistant runs on ours, a request goes to Anthropic. There is no organisation-level policy to restrict providers yet, and no published subprocessor list; both are said below rather than left out.
The interview summary is the second path, and the only one a transcript takes. When an owner, admin or recruiter asks for a draft of a round, that interview’s transcript and timeline, the interviewer’s notes, the names of what the candidate produced, the filed scorecards, and the job’s brief and requirements go to Anthropic for that one draft; asking for the overall assessment sends the candidate’s name, the round summaries and the scored table; drafting requirements sends the job description. A viewer cannot ask, so nothing goes for a viewer, and nothing goes unasked — no summary is drafted on a schedule. One setting per organisation turns all of it off, refused on the server before anything leaves; it is not yet a switch in the app, so ask us to set it. Nothing said in an interview is written to a log, including when the call fails.
- Does our data reach an AI provider, and is it used for training?
- partial
Only if a customer uses the assistant. Where the interviewer has their own Claude installed it runs on their machine and nothing is relayed to us. Otherwise a request goes to Anthropic. There is no organization-level policy to restrict providers yet, and no central layer recording exactly what is sent.
To close it: One AI provider layer that records what is sent where, and a per-organization policy over it.
- Who are your subprocessors?
- partial
Hosting and database, media relay, email delivery, and an AI provider when the assistant is used. There is no published subprocessor list yet.
To close it: A maintained subprocessor list with what each receives and why.
- What access do your integrations request?
- in placemeasured live in the app
Calendar access is read-only and free/busy where the provider supports it. The one exception is the interview we booked ourselves: we read that single event on the booker's own calendar to show who has accepted, by the identifier we put on the invitation, and nothing else on the calendar with it. ATS imports of job postings need no key at all for three of the five providers. Every connection records who made it and when.
- What do you store from our ATS?
- in place
For job postings: an external id, a title, a location and a URL. Greenhouse returns dozens of fields per job; four are kept. Candidate records are only created when a customer imports them.
What is not built, said plainly.
7 answers are no and 13 are partial. They are listed here in full because a page that hides them is not worth reading, and because each one carries what would close it. The full register, area by area, follows; inside the app the same page is the Security tab.
- Do you support SAML or OIDC single sign-on, and SCIM provisioning?
- not done
Not yet. The identity model is email-or-OAuth with a session table, which is compatible with adding them — no password store would have to be unwound first.
To close it: A SAML/OIDC provider per organization, and SCIM for provisioning and deprovisioning.
- How do you handle vulnerable dependencies?
- not done
Lockfiles are committed. There is no automated scanning or update policy, and secret scanning on private repositories is a paid add-on we do not have.
To close it: Dependabot or equivalent, plus a triage expectation.
- How are desktop builds signed and updated?
- not done
Code signing is configured for macOS and Windows but not yet issued, so builds are unsigned today. There is no auto-update channel, which also means there is nothing to hijack.
To close it: Signing certificates in place, a signed update channel, and the ability to stop a bad release.
- Are development and production separated?
- not done
There is one database, and development runs against it. That is the weakest answer on this page. Another product's tables also share the instance.
To close it: A separate development database, seeded rather than copied from production.
- What happens if you have a breach?
- not done
There is no written incident response plan. The architecture supports investigation — an audit log, credential revocation and per-integration disconnection — but the process around it is not documented.
To close it: A runbook: what counts as an incident, who is notified, how credentials rotate, how customers are identified and told.
- Have you had a penetration test?
- not done
No. The boundaries most worth testing — tenant isolation and authorization — are covered by automated checks that run on every push, but that is not a substitute for somebody trying to break in.
To close it: An external test once the surface is stable.
- Do you have SOC 2?
- not done
No, and we will not claim otherwise. The architecture is being built so that certification becomes documenting controls that already exist rather than a rewrite. This page is part of that.
To close it: Type I after the controls above are in place; Type II after an observation window.
- Do you support multi-factor authentication?
- partial
Not directly. Where sign-in is through GitHub, that account's MFA applies. The email link path has no second factor of its own.
To close it: MFA on the email path, and an organization setting to require it.
- How are sessions handled and revoked?
- partial
Sessions are server-side rows with an expiry, checked on every request. Signing out (POST /api/auth/signout) deletes the row the cookie names and clears the cookie, so a session ends when the person ends it rather than when the clock does. There is no per-device session list yet, so a session on a machine you no longer hold cannot be ended from another one.
To close it: Visible device and session list, with revoke.
- Can a recruiter see another recruiter’s pipeline?
- partialmeasured live in the app
By default yes, and on purpose. Membership carries a second axis beside the role -- a scope of org, teams or own -- and every member starts at org, which is exactly what they had before scopes existed; narrowing somebody silently would be the worse failure. An administrator can set a member to their teams or to the roles they own, and from then on every read is fenced to those roles in the query rather than filtered after it: the roles list, the candidates, the schedule, the board, the debrief, what needs them, and the assistant's tools, because a candidate, an interview and a round all hang off a role. A candidate nobody has assigned to a role yet belongs to no scope, and is reachable only by a seat that holds the grant to assign them. Scope only ever narrows -- it is applied on top of the permission check, never instead of one. Read this one as weaker than the tenancy rows above it and do not read the two as equal: scope is enforced by the application, in every query, with a static check in CI over the routes and a test that drives the real handlers -- there is no policy in the database underneath it, as there is for tenant isolation. It is a policy about who inside one customer's account sees whose work, not the boundary between two customers. The measurement below is who is narrowed in this organization today.
To close it: A screen for setting a member’s scope, and reassignment of a role’s owner from the app rather than only over the API.
- Could a secret end up in your logs?
- partial
Redaction happens in the audit helper rather than at each call site, catching credentials both by field name and by the shape of the value, at any depth. Application logs are less rigorous and are the weaker half of this answer.
To close it: A structured logger with the same redaction applied to application logs.
- Do you classify data by sensitivity?
- partial
Four levels, with candidate PII, transcripts, deliverables, scorecards, OAuth tokens and customer source code all treated as the most sensitive. It governs logging, retention and access.
To close it: The classification applied per column rather than held as documentation.
- How long do you keep candidate data?
- partialmeasured live in the app
For as long as you tell us to, and by default forever. You are the controller and we are the processor, so we supply the control and you set the period: eight classes of content -- transcripts, recordings, deliverables, CVs and files, free-text notes, messages, drafted summaries, scorecard notes -- each with its own number of days, each unset until somebody sets it. An organization that sets nothing loses nothing, deliberately: employers are required to retain hiring records, and a product that quietly destroyed them would be the worse failure. What a period expires is the content; the decision record stays -- who applied, to which role, when, which stages they reached, who assessed them, the verdict and the outcome -- because expiry empties columns rather than deleting rows. Scorecards are the defence rather than the exposure, so their period cannot be shorter than any other class's and only their free text ever goes. Closing a role starts the clock for what belongs to the application; an interview ending starts it for what the session produced. A legal hold suspends all of it. The job runs on the existing cron, is bounded and idempotent, and records what it expired. The screen is in the app: an admin sets a period per class, places and releases a legal hold, and files an erasure, with the measurement beside each class. Two limits remain, both honest rather than hidden. Content anchored on a role that is not both archived and dated never expires, so a policy set by an organization that never closes its roles does nothing. And the screen cannot yet show exactly what a period would reach before it is set: the measurement computes against the period in force, so a proposed number is bounded rather than counted, and the true figure is re-read the moment the period is saved.
To close it: A dry run, so setting a period shows exactly what it would empty before it is saved rather than a bound on it; and a signal for a role that is archived without being closed, whose content a policy can never reach.
- Where is data stored, and can we choose the region?
- partial
United States, on managed infrastructure. There is no regional choice, which is a gap for customers with EU residency requirements.
To close it: A region per organization, and a data map to support it.
- It is an Electron app. How is it hardened?
- partial
Context isolation is on and node integration is off in the renderer, which is one local document that may not navigate anywhere else; new windows are refused and links open in the person's own browser. A Content Security Policy forbids inline and remote script. Pages may ask the OS only for the camera, microphone, screen, fullscreen and clipboard write. The preview's embedded page gets no preload and no Node, is sandboxed, and may only point at this machine. File access over IPC — the tree, reads, writes, the profile read-back and the workspace snapshot — is confined to the workspaces the main process itself opened, resolved through symlinks so a link committed into a repository cannot point out of it; repository status, change-watching and reveal-in-Finder still take a renderer-supplied root and leak only metadata. The candidate's shell starts from an allowlisted environment rather than the app's own. The renderer itself does not yet run under Electron's sandbox, and IPC payloads are checked by the handlers that take paths rather than validated as a whole.
To close it: Electron's `sandbox` on the renderer, and schema validation on every IPC payload rather than only on the handlers that take paths.
- Does our data reach an AI provider, and is it used for training?
- partial
Only if a customer uses the assistant. Where the interviewer has their own Claude installed it runs on their machine and nothing is relayed to us. Otherwise a request goes to Anthropic. There is no organization-level policy to restrict providers yet, and no central layer recording exactly what is sent.
To close it: One AI provider layer that records what is sent where, and a per-organization policy over it.
- Who are your subprocessors?
- partial
Hosting and database, media relay, email delivery, and an AI provider when the assistant is used. There is no published subprocessor list yet.
To close it: A maintained subprocessor list with what each receives and why.
- What runs before code ships?
- partial
Type checking, a build, and the full test suite on every push, against a real database the workflow starts for itself and builds from the migrations. That last part matters: without a database the tenant isolation and row-level-security tests skipped in silence, so the checks that mattered most were the ones not running. A deploy is now gated on those checks passing for the exact commit being deployed. Deploys still leave from a developer machine rather than from CI.
To close it: Deploys triggered by CI rather than gated by it, protected branches, and dependency and secret scanning.
- What are your backup and recovery arrangements?
- partial
Automated backups are provided by the managed database. No restore has been tested, so recovery time is unproven.
To close it: A tested restore on a schedule, with the result recorded.
- Which of your staff can reach customer data?
- partial
Production database credentials are held by one person. There is no separate staff access path into a customer account, and no support impersonation.
To close it: Named roles for production access, with the access itself audited.

The whole register
Every question, by area, with its state. This is lib/controls.ts rendered, not summarised; a Security seat sees exactly this, with the seven measured rows checked live.
Tenancy
- How do you keep one customer's data away from another's?
- in placemeasured live in the app
Every tenant-owned table carries an org_id, and every read scopes to it in the query rather than filtering afterwards. A static check in CI fails the build if any route reads a whole tenant table.
- Is isolation enforced at the database as well as the application?
- in placemeasured live in the app
Yes. Every statement runs as its organization -- a transaction-local setting the database reads -- and every tenant table carries a policy that returns no rows when that setting is absent and refuses a write that would land in another organization. The application connects as a role without BYPASSRLS, so the database, not just the code, is what refuses. The measurement below is the live state, role included.
- Do you test for cross-tenant access?
- in place
Yes, two ways: a static check over every API route that runs on each push, and a live-data assertion that every tenant row is attributed. The static one found a real leak that code review had missed three times.
Encryption
- Is data encrypted in transit?
- in place
Yes. All API traffic is HTTPS, and the interview room's media and data channels are WebRTC with DTLS-SRTP.
- Are credentials and interview content encrypted at rest?
- in placemeasured live in the app
Yes. OAuth access and refresh tokens and ATS API keys (Greenhouse, Ashby, Lever, SmartRecruiters, Workable) are sealed with AES-256-GCM before they reach the database, with a per-value IV and an authentication tag. The key comes from the platform's secret store, never from the application. An ATS key stored before sealing existed is re-sealed the next time it is read. Since 7 Sep interview content is sealed the same way before it reaches the database: transcripts, timelines and notes, the files a candidate produced, dataset bodies, and the drafted summaries and assessments (lib/content.ts); every existing row was sealed by a backfill the same day; a write without the key is refused rather than stored in the clear. Scorecard notes and message bodies are not yet sealed.
- Is the database encrypted at rest?
- in place
Yes, by the managed provider. Worth noting this protects the disk, not the row — which is why credentials are separately sealed above.
- Where do encryption keys live?
- in place
In the deployment platform's encrypted environment store, and in a local .env for development. Never in source control — a key the application can mint would end up in the same backup as the data it protects.
Identity
- How do users authenticate?
- in place
GitHub OAuth, or a single-use email link that expires in fifteen minutes. There are no passwords, so there is no password store to breach or policy to enforce.
- Do you support multi-factor authentication?
- partial
Not directly. Where sign-in is through GitHub, that account's MFA applies. The email link path has no second factor of its own.
To close it: MFA on the email path, and an organization setting to require it.
- Do you support SAML or OIDC single sign-on, and SCIM provisioning?
- not done
Not yet. The identity model is email-or-OAuth with a session table, which is compatible with adding them — no password store would have to be unwound first.
To close it: A SAML/OIDC provider per organization, and SCIM for provisioning and deprovisioning.
- How are sessions handled and revoked?
- partial
Sessions are server-side rows with an expiry, checked on every request. Signing out (POST /api/auth/signout) deletes the row the cookie names and clears the cookie, so a session ends when the person ends it rather than when the clock does. There is no per-device session list yet, so a session on a machine you no longer hold cannot be ended from another one.
To close it: Visible device and session list, with revoke.
Access control
- How is authorization enforced?
- in placemeasured live in the app
One permission model. Permissions are named for what they protect rather than who holds them, and every check asks can(role, permission). An unknown role holds nothing, so a typo fails closed.
- Can somebody reviewing your security see candidate data?
- in place
No. The Security role reads every control, integration and audit entry, and no candidate, transcript, deliverable or scorecard. An auditor who can change what they audit is not an auditor.
- Can a recruiter see another recruiter’s pipeline?
- partialmeasured live in the app
By default yes, and on purpose. Membership carries a second axis beside the role -- a scope of org, teams or own -- and every member starts at org, which is exactly what they had before scopes existed; narrowing somebody silently would be the worse failure. An administrator can set a member to their teams or to the roles they own, and from then on every read is fenced to those roles in the query rather than filtered after it: the roles list, the candidates, the schedule, the board, the debrief, what needs them, and the assistant's tools, because a candidate, an interview and a round all hang off a role. A candidate nobody has assigned to a role yet belongs to no scope, and is reachable only by a seat that holds the grant to assign them. Scope only ever narrows -- it is applied on top of the permission check, never instead of one. Read this one as weaker than the tenancy rows above it and do not read the two as equal: scope is enforced by the application, in every query, with a static check in CI over the routes and a test that drives the real handlers -- there is no policy in the database underneath it, as there is for tenant isolation. It is a policy about who inside one customer's account sees whose work, not the boundary between two customers. The measurement below is who is narrowed in this organization today.
To close it: A screen for setting a member’s scope, and reassignment of a role’s owner from the app rather than only over the API.
- Can any employee of yours view a customer's data?
- in place
Only an account owner can view their own organization through another member's eyes, and only within that organization. It cannot be used to climb, and the real identity is carried alongside: every audit event and configuration snapshot names the owner as the actor and records the seat they were viewing from. Deploy Ready staff have no such route into a customer account.
Accountability
- Do you keep an audit log, and can it be tampered with?
- in placemeasured live in the app
Yes, and there is no write path from a client — events are recorded from inside the action that caused them. Nothing updates or deletes a row. Reading the log is itself an audited event, and a refused read is recorded as denied. A reader who holds audit.read without the candidate grant — the Security seat — sees the log with the people redacted: an actor who is not a member of the organization is shown as "a candidate", the label of an object that names a person is withheld, and each event's meta is reduced to an allowlist of keys that carry counts and the names of things.
- Could a secret end up in your logs?
- partial
Redaction happens in the audit helper rather than at each call site, catching credentials both by field name and by the shape of the value, at any depth. Application logs are less rigorous and are the weaker half of this answer.
To close it: A structured logger with the same redaction applied to application logs.
Data
- Do you classify data by sensitivity?
- partial
Four levels, with candidate PII, transcripts, deliverables, scorecards, OAuth tokens and customer source code all treated as the most sensitive. It governs logging, retention and access.
To close it: The classification applied per column rather than held as documentation.
- How long do you keep candidate data?
- partialmeasured live in the app
For as long as you tell us to, and by default forever. You are the controller and we are the processor, so we supply the control and you set the period: eight classes of content -- transcripts, recordings, deliverables, CVs and files, free-text notes, messages, drafted summaries, scorecard notes -- each with its own number of days, each unset until somebody sets it. An organization that sets nothing loses nothing, deliberately: employers are required to retain hiring records, and a product that quietly destroyed them would be the worse failure. What a period expires is the content; the decision record stays -- who applied, to which role, when, which stages they reached, who assessed them, the verdict and the outcome -- because expiry empties columns rather than deleting rows. Scorecards are the defence rather than the exposure, so their period cannot be shorter than any other class's and only their free text ever goes. Closing a role starts the clock for what belongs to the application; an interview ending starts it for what the session produced. A legal hold suspends all of it. The job runs on the existing cron, is bounded and idempotent, and records what it expired. The screen is in the app: an admin sets a period per class, places and releases a legal hold, and files an erasure, with the measurement beside each class. Two limits remain, both honest rather than hidden. Content anchored on a role that is not both archived and dated never expires, so a policy set by an organization that never closes its roles does nothing. And the screen cannot yet show exactly what a period would reach before it is set: the measurement computes against the period in force, so a proposed number is bounded rather than counted, and the true figure is re-read the moment the period is saved.
To close it: A dry run, so setting a period shows exactly what it would empty before it is saved rather than a bound on it; and a signal for a role that is archived without being closed, whose content a policy can never reach.
- Can you delete a candidate's data on request?
- in place
Yes. One operation erases a person across every store this product has -- every class of content in every table it lives in, plus the identifiers themselves, which no retention period ever touches -- and writes the row count per table onto the request and into the audit log, so completion is a number rather than an assurance. Uploads are rows in this database, not objects in a bucket, so "every store" is the database; if that ever changes it changes in the same function. It overrides the retention schedule and it refuses while a legal hold stands, saying so, because destroying evidence in a live dispute at the subject's request is still destroying evidence. Two things it leaves alone on purpose: the audit log, which is append-only and carries identifiers rather than content, and the candidate's own account with us, which is a different controller reached by a different door.
- What do you store from our ATS?
- in place
For job postings: an external id, a title, a location and a URL. Greenhouse returns dozens of fields per job; four are kept. Candidate records are only created when a customer imports them.
- Where is data stored, and can we choose the region?
- partial
United States, on managed infrastructure. There is no regional choice, which is a gap for customers with EU residency requirements.
To close it: A region per organization, and a data map to support it.
Interview room
- Candidate code runs somewhere. Where, and how is it contained?
- in place
On the candidate's own machine, in their own shell, as them. We are not a sandbox and do not claim to be one — the boundary is that their machine is neither ours nor the interviewer's. Nothing a candidate writes executes on our infrastructure.
- It is an Electron app. How is it hardened?
- partial
Context isolation is on and node integration is off in the renderer, which is one local document that may not navigate anywhere else; new windows are refused and links open in the person's own browser. A Content Security Policy forbids inline and remote script. Pages may ask the OS only for the camera, microphone, screen, fullscreen and clipboard write. The preview's embedded page gets no preload and no Node, is sandboxed, and may only point at this machine. File access over IPC — the tree, reads, writes, the profile read-back and the workspace snapshot — is confined to the workspaces the main process itself opened, resolved through symlinks so a link committed into a repository cannot point out of it; repository status, change-watching and reveal-in-Finder still take a renderer-supplied root and leak only metadata. The candidate's shell starts from an allowlisted environment rather than the app's own. The renderer itself does not yet run under Electron's sandbox, and IPC payloads are checked by the handlers that take paths rather than validated as a whole.
To close it: Electron's `sandbox` on the renderer, and schema validation on every IPC payload rather than only on the handlers that take paths.
- Do you record interviews?
- does not apply
No. There is no video or audio recording, by choice. A transcript is produced from speech on each participant's own machine, and the code the candidate wrote is stored as a deliverable.
- What monitoring runs on a candidate's machine?
- in place
Only with their explicit consent, shown as a full list before anything runs, and declining is recorded rather than penalised. It never reads their screen, keystrokes, files or other applications, and cannot prevent anything from running. We can detect, with permission; we cannot enforce, and do not claim to.
Third parties
- What access do your integrations request?
- in placemeasured live in the app
Calendar access is read-only and free/busy where the provider supports it. The one exception is the interview we booked ourselves: we read that single event on the booker's own calendar to show who has accepted, by the identifier we put on the invitation, and nothing else on the calendar with it. ATS imports of job postings need no key at all for three of the five providers. Every connection records who made it and when.
- Does our data reach an AI provider, and is it used for training?
- partial
Only if a customer uses the assistant. Where the interviewer has their own Claude installed it runs on their machine and nothing is relayed to us. Otherwise a request goes to Anthropic. There is no organization-level policy to restrict providers yet, and no central layer recording exactly what is sent.
To close it: One AI provider layer that records what is sent where, and a per-organization policy over it.
- Who are your subprocessors?
- partial
Hosting and database, media relay, email delivery, and an AI provider when the assistant is used. There is no published subprocessor list yet.
To close it: A maintained subprocessor list with what each receives and why.
Engineering
- What runs before code ships?
- partial
Type checking, a build, and the full test suite on every push, against a real database the workflow starts for itself and builds from the migrations. That last part matters: without a database the tenant isolation and row-level-security tests skipped in silence, so the checks that mattered most were the ones not running. A deploy is now gated on those checks passing for the exact commit being deployed. Deploys still leave from a developer machine rather than from CI.
To close it: Deploys triggered by CI rather than gated by it, protected branches, and dependency and secret scanning.
- How do you handle vulnerable dependencies?
- not done
Lockfiles are committed. There is no automated scanning or update policy, and secret scanning on private repositories is a paid add-on we do not have.
To close it: Dependabot or equivalent, plus a triage expectation.
- How are desktop builds signed and updated?
- not done
Code signing is configured for macOS and Windows but not yet issued, so builds are unsigned today. There is no auto-update channel, which also means there is nothing to hijack.
To close it: Signing certificates in place, a signed update channel, and the ability to stop a bad release.
- Are development and production separated?
- not done
There is one database, and development runs against it. That is the weakest answer on this page. Another product's tables also share the instance.
To close it: A separate development database, seeded rather than copied from production.
- What are your backup and recovery arrangements?
- partial
Automated backups are provided by the managed database. No restore has been tested, so recovery time is unproven.
To close it: A tested restore on a schedule, with the result recorded.
Operations
- What happens if you have a breach?
- not done
There is no written incident response plan. The architecture supports investigation — an audit log, credential revocation and per-integration disconnection — but the process around it is not documented.
To close it: A runbook: what counts as an incident, who is notified, how credentials rotate, how customers are identified and told.
- Have you had a penetration test?
- not done
No. The boundaries most worth testing — tenant isolation and authorization — are covered by automated checks that run on every push, but that is not a substitute for somebody trying to break in.
To close it: An external test once the surface is stable.
- Do you have SOC 2?
- not done
No, and we will not claim otherwise. The architecture is being built so that certification becomes documenting controls that already exist rather than a rewrite. This page is part of that.
To close it: Type I after the controls above are in place; Type II after an observation window.
- Which of your staff can reach customer data?
- partial
Production database credentials are held by one person. There is no separate staff access path into a customer account, and no support impersonation.
To close it: Named roles for production access, with the access itself audited.
A Security seat can be invited today, at no cost, and can review a sandbox organisation with nobody real in it. What it cannot yet do is run each verification itself from this page; that is on the roadmap, and until it is, the register points at the code and the tests instead. Every change to how you interview is kept separately, as a version — history.
Send this page to whoever has to sign it off.
It says the same thing the app does, in the same words, and it is allowed to say no. Ten interviews a month, free, on the whole product; a Security seat is free on every plan.