Privacy
What Hawkeye stores, what it never stores, and how to get it all back or gone.
Last reviewed 2026-09-03. Written to be checked against the code, not to be skimmed.
Hawkeye takes privileged actions on machines you own — running commands, moving files, driving a signed-in desktop. A product like that has to be unusually specific about what it keeps, so this page lists the actual database tables rather than a category like "usage data".
What is stored, where it lives, and who else touches it
The control plane runs as a Cloudflare Worker over a single Cloudflare D1 (SQLite)
database, an R2 bucket for objects, and short-lived KV counters. The table below is
rendered from the product's own data registry
(worker/src/panel/dataregistry.ts), not written by hand: every class names
the real tables, prefixes or files it lives in, and a release check fails if the code
grows a table or a processor this page does not carry.
| What it is | Where it is stored | Who processes it | How long it stays | Export and deletion |
|---|---|---|---|---|
| Your account your email address (lowercased), an optional display name, when you signed up and last signed in, and a PBKDF2 hash of your password. The password itself is never written down and no code path can read it back. If you registered a passkey: its credential id, its COSE public key, the label you gave it, and when it was last used — never the private key, which stays on your device's authenticator. |
Cloudflare D1 (the control-plane database): users, oauth_identities, webauthn_credentials | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Your organisation its slug, display name, plan and settings, who belongs to it and at what role, the teams and projects inside it, and which parts of the first-run checklist you have dismissed. |
Cloudflare D1 (the control-plane database): orgs, memberships, teams, team_members, projects, platform_admins, signup_grants, onboarding_dismissed, firstrun_prefs, cloud_computer_interest, comp_codes | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Retired organisation identifier after a self-service deletion completes, the former organisation slug and retirement time are retained so an old session, controller credential or delayed request cannot attach to a later tenant under the same public name. It does not retain the organisation name, members, settings, files or cloud resource records. |
Cloudflare D1 (the control-plane database): retired_org_slugs | Cloudflare | kept for the life of the deployment; there is no scheduled purge because reuse would re-open the stale-authority race | withheld from the export created atomically when the org is deleted and intentionally retained as a non-reusable namespace guard |
| Sign-ins for each live session: a session id, a CSRF token, the IP address and browser user-agent it was created from, and its expiry. Separately, the IP and timestamp of each login attempt, so brute force can be rate limited. And, for the few minutes a passkey sign-in or registration is actually in progress: a one-time server-issued challenge. |
Cloudflare D1 (the control-plane database): sessions, login_attempts, webauthn_challenges; your own browser: hk_sess | Cloudflare | a session carries its own expiry and is refused past it; failed-login records for one address are cleared when that account's password is reset (worker/src/panel/apptokens.ts:769). A passkey challenge is deleted the instant it is READ back, whether or not it verifies, and is refused as expired after 5 minutes either way (worker/src/panel/passkey.ts's CHALLENGE_TTL_S) — but an abandoned ceremony nobody ever completes leaves that one small row (a random challenge value, no email or name) sitting until something reads it. None of the three is swept on a fixed schedule | withheld from the export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Paired apps and runtimes a phone, desktop app or agent runtime you paired: its name, platform, the scopes you granted, when it was created and last seen, its heartbeats, and any work item queued for it. |
Cloudflare D1 (the control-plane database): app_devices, app_device_roots, app_device_org_grants, app_scope_upgrades, app_pairings, mobile_auth_codes, session_attestations, session_heartbeats, product_workload_sessions, product_workload_client_ids, product_workload_heartbeats, product_workload_inbox_items, product_workload_inbox_state | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Credential verifiers install links, access and refresh tokens, one-time password-reset and email-verification tokens, approval nonces and download tickets — all stored as a hash or an opaque id, single use, with an expiry. The plaintext is shown to you once at creation and is never recoverable afterwards, including by us. |
Cloudflare D1 (the control-plane database): installs, password_reset_tokens, email_verification_tokens, app_tokens, app_pairing_action_nonces, approval_used, xfer_tickets | Cloudflare | each row carries an expiry and is refused past it; spent approval nonces are deleted opportunistically (worker/src/panel/apptokens.ts:1003). Nothing else is swept on a schedule | withheld from the export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Invitations and access requests the email address an invitation was sent to, the role it offers, who created it and when it expires — with the invitation token itself held only as a hash. |
Cloudflare D1 (the control-plane database): invites, access_requests, person_invites | Cloudflare, Resend | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Your machines hostname, the machine's public key, which group and teams it is in, its enrolment state and when it was last seen, the policy attached to it, the name of the Worker secret that reaches it, and the machine's public receiving key for encrypted memory with the signature binding it to that same machine — the private half is generated on the machine and never sent. |
Cloudflare D1 (the control-plane database): machines, devices, enrollments, join_keys, org_boxes, box_secret_claims, policies, computer_placement_preferences; Cloudflare D1 (the control-plane database): enrollment_receiving_keys, device_receiving_keys, device_reconciliation_notices | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| People you can route work to the directory of humans an org can send a decision or an invitation to: a display name, the groups they are in, and the identities you attach so a reply can be matched to a person. |
Cloudflare D1 (the control-plane database): people, person_identities, person_groups, person_group_members, identity_verification_tokens | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Notification destinations the destination you type in — an email address, a phone number or a Slack webhook — plus the severity threshold you chose. Every channel is optional and off until you add it. |
Cloudflare D1 (the control-plane database): notification_channels | Cloudflare, Resend, Twilio, Slack | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Notifications the notifications the product raised for your org: severity, title, body and source. |
Cloudflare D1 (the control-plane database): notifications | Cloudflare, Resend, Twilio, Slack, Google | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| The org stop switch and its record whether your org is currently stopped, who engaged or released it, when, why, and from which IP — plus the pairings whose outstanding queue tickets were revoked. They are named here because a table the product creates and this registry does not mention is exactly the gap this file exists to close. |
Cloudflare D1 (the control-plane database): org_kill_switch; Cloudflare D1 (the control-plane database): kill_events; Cloudflare D1 (the control-plane database): bridge_ticket_revocations | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Platform-refuse confirmation code for a platform admin who has started confirming the whole-deployment stop: a hashed one-time code, when it expires, and how many times it has been tried. Named here for the same reason the kill-switch entry above is: a table the product creates and this registry does not mention is the gap this file exists to close. This one is NOT an org's data — it names no org at all, only the admin account confirming the action, and is a platform-wide capability, not a tenant one (see auth.ts's isPlatformAdmin). |
Cloudflare D1 (the control-plane database): platform_refuse_challenges | Cloudflare, Resend | one row per admin, overwritten by their next challenge; deleted on a successful confirm and never kept past its own 300-second expiry otherwise — there is no scheduled purge because nothing here survives long enough to need one | not ours to export not org data and never swept by the org-deletion cascade in account.ts — it holds no org id, only a platform admin's own in-flight confirmation attempt |
| Global refusal break-glass recovery code one hashed, single-use code per refusal scope, minted only once (in the response body of a genuine engage) so a platform admin can still release a global refusal if the email channel the ordinary two-factor path depends on is down. Named here for the same reason the two entries above are: a table the product creates and this registry does not mention is the gap this file exists to close. Not an org's data — it names no org at all, only a refusal scope and the admin who engaged it. |
Cloudflare D1 (the control-plane database): platform_refuse_recovery_codes | Cloudflare | one row per scope, deleted on successful consumption (single-use) or replaced by the next real engage; nothing here survives past the refusal it was minted for | not ours to export not org data and never swept by the org-deletion cascade in account.ts — it holds no org id, only a platform admin's own break-glass recovery material |
| The audit trail for each privileged action: when, which org, which user, what action, on what target, and the source IP. This is the record the product is sold on; it is deliberately hard to make disappear. |
Cloudflare D1 (the control-plane database): panel_audit; Cloudflare D1 (the control-plane database): audit | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export your org's audit rows go with the org, but ONE deployment-level row survives it: a record, with no org id, that the deletion happened and who asked for it (worker/src/panel/account.ts:793). Keeping no evidence that we deleted something is not a record |
| The activity feed the canonical event spine behind the timeline: what happened, to what, and when. |
Cloudflare D1 (the control-plane database): activity_events | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Hosted cloud coding workspaces for each isolated coding machine you ask us to run: its name, the repository URL and ref you selected, the size and budget policy you set, its lifecycle history, what it has cost so far, and the short-lived credentials that let one guest machine enrol itself and let your browser attach to its terminal. The code, files and shell output inside the workspace live on that machine, not in this database; what is recorded here is the workspace's management record. A separately scheduled discard-at-expiry intent records its exact workspace generation, deadline and consenting identity, but it cannot execute deletion. If you connect GitHub, the service records the selected project's installation account, authorization revision and any explicit time-limited push grants. OAuth callback values, provider tokens, webhook bodies and native possession proofs are not stored. The org export carries these rows without the ticket, enrolment and lease verifiers themselves: those are live credentials, not a record (worker/src/panel/orgdata.ts, TABLE_TREATMENT withhold). |
Cloudflare D1 (the control-plane database): cloud_workspaces; Cloudflare D1 (the control-plane database): cloud_retention_jobs; Cloudflare D1 (the control-plane database): cloud_operations; Cloudflare D1 (the control-plane database): cloud_workspace_events; Cloudflare D1 (the control-plane database): cloud_execution_leases; Cloudflare D1 (the control-plane database): cloud_controller_leases; Cloudflare D1 (the control-plane database): cloud_budget_accounts; Cloudflare D1 (the control-plane database): cloud_workspace_enrollments; Cloudflare D1 (the control-plane database): cloud_terminal_tickets; Cloudflare D1 (the control-plane database): cloud_terminal_routes; Cloudflare D1 (the control-plane database): cloud_terminal_nonces; Cloudflare D1 (the control-plane database): cloud_github_project_installations, cloud_github_installation_states, cloud_github_webhook_deliveries; Cloudflare D1 (the control-plane database): cloud_repository_credential_uses, cloud_repository_push_grants | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| GitHub installation change fence when a connected GitHub App installation changes, the service keeps its numeric installation id, a monotonic change counter, the most recent webhook delivery id and the update time. It keeps no organization id, user id, repository name, webhook body, OAuth value or provider token. The global counter prevents a consent callback captured before a revocation or permission change from becoming current later. |
Cloudflare D1 (the control-plane database): cloud_github_installation_events | Cloudflare | kept for the life of the deployment; the schema makes the monotonic fence durable and no scheduled purge removes it | withheld from the export not covered by org deletion — this is a deployment-level provider event fence with no org id, retained so deleting one tenant cannot reopen a stale consent callback |
| Which OAuth app this deployment uses per connector for each third-party connector (Google, Slack, GitHub, Notion, Linear, ...), which OAuth application id this DEPLOYMENT registered with that provider, a pointer to the client secret held as a Worker secret (never the secret value itself), and that authorization server's cached discovery metadata (its token/authorization endpoints). This is operational configuration an operator provisions once per deployment, shared by every org — it names no user, no org, and no individual's connection.. |
Cloudflare D1 (the control-plane database): connector_clients | Cloudflare | kept for the life of the deployment; re-provisioning overwrites the row in place | not ours to export not covered by org deletion — this is deployment-level configuration shared by every org, not one tenant's data |
| Cloud resource cleanup journal after a hosted workspace allocation is issued, the protected controller keeps its organization and workspace ids, generation, provider project, immutable resource ids and self-links, Hawkeye ownership labels, requested data disposition, cleanup state, and final evidence digests. It does not store repository contents, shell output, provider credentials, controller bearer tokens, or customer encryption keys. The journal remains independent of the account database so deleting an account cannot erase the only record needed to find and stop a paid resource. |
the protected Hawkeye cloud-controller host: destruction/cloud-destruction.sqlite3 | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | withheld from the export it deliberately does not go with the organization row: already-authorized cleanup must finish after a controller restart, and the minimal final resource/cost/custody tombstone remains in the protected controller journal. No automatic purge period has been set |
| Outbound control connections from your machines for a machine of yours that dials out to us instead of us reaching in to it (worker/src/panel/dialout.ts): which machine is currently holding a connection, when it connected, when we last heard from it, and the version of the agent it is running. Plus two short-lived verifiers -- a single-use connection ticket, stored only as a SHA-256 and never as the ticket itself, and the one-use nonces that stop a connection proof being replayed. Both expire in about a minute and are swept. WHAT IS NOT HERE: the requests pushed down the connection and their replies. Those are relayed live between the worker and your machine and are never written to this database. |
Cloudflare D1 (the control-plane database): dialout_routes; Cloudflare D1 (the control-plane database): dialout_tickets; Cloudflare D1 (the control-plane database): dialout_nonces | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Approval requests and their answers a question an agent raised for a human, where it was sent, and the answer that came back. The question and answer text is whatever the requester wrote. |
Cloudflare D1 (the control-plane database): decisions, decision_dispatches, decision_responses, enroll_slack | Cloudflare, Slack | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Lead agent commands and autonomy settings the org's own configured autonomy per action category (autonomous vs. requires approval, the approval timeout, and who may approve), plus the structured record of each command an owner escalated to a human for approval (its category, instruction text and requesting device) so the approval can actually be carried out if a human allows it. The delegated credential minted to carry out an approved or autonomous command is never written to either table -- it lives only as an ordinary, already-disclosed access token (see "Paired app devices") with a roughly two-minute lifetime. |
Cloudflare D1 (the control-plane database): lead_agent_policies, lead_agent_commands | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Geographic provenance rules for file transfers and vault access a rule you configure naming a source region, a destination region, and whether that combination is allowed, requires approval, or is blocked for file-transfer or vault-access actions. A rule requiring approval also names who is asked (the same person/group format as approval requests, above) and reuses that same approval mechanism -- it is not a second store of decisions. |
Cloudflare D1 (the control-plane database): geo_provenance_rules | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Agent specs, conversations and workflows the agents you define, the conversations and workflow steps they run, and the relay cursor that keeps two machines' agent channels in step. #907: a message you send in a conversation, and recent excerpts of that same conversation quoted as context, are sent to a model to produce Hawkeye's reply — to YOUR provider on YOUR key when your org has connected one, and otherwise to the shared house account, and only for a conversation that is not bound to one of your own machines (a bound one is relayed to that machine instead and reaches no model provider from here). |
Cloudflare D1 (the control-plane database): agent_specs, agent_spec_revisions, conversations, conversation_events, instances, workflows, workflow_steps, chat_relay_cursor | Cloudflare, Anthropic, OpenAI, OpenRouter, Google | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Harness rules and templates the operating rules your org's agents run under -- which capabilities are pre-approved vs. require an admin's approval, communication and audit conventions -- plus the starter template every org is seeded with and any personal copies members have forked from it, and any pending proposals to change the org's live rules. |
Cloudflare D1 (the control-plane database): harness_rule_sets, harness_rule_proposals | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Hawkeye's memory of your conversations short sentences a model wrote about what was said in your panel conversations — a decision, a preference, a name, a number — each one stored with a pointer back to the message it came from, so Hawkeye can recall it in a later conversation instead of forgetting it after eight messages. Producing them sends recent excerpts of that conversation to a model, exactly as answering you already does: to YOUR provider on YOUR key when your org has connected one, and otherwise to the shared house account. It happens only AFTER a reply has been sent, only for a conversation that is not bound to one of your own machines (a bound one is relayed to that machine and reaches no model provider, and is never remembered here), and it is capped per org per day. The second table is the ledger of every extraction attempt, including the ones that produced nothing and the ones that failed. |
Cloudflare D1 (the control-plane database): memory_facts, memory_facts_fts, memory_capture_runs | Cloudflare, Anthropic, OpenAI, OpenRouter, Google | Not decided yet: how long an extracted memory is kept when nothing ever retrieves it. Today it is kept until you delete the org, like everything else here, and there is no scheduled purge. | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Remote desktop grants and frames who may view or drive which machine, the short-lived screen frames a viewer is served, and the operator lease saying who currently holds the machine. |
Cloudflare D1 (the control-plane database): operate_grants, operate_frames, operate_intents, operator_leases, operator_handovers | Cloudflare | a frame and an intent are short-lived by design and carry a machine id rather than a person; nothing sweeps them on a schedule, and the two of them are the only org-scoped tables the deletion cascade does not name, because neither carries an org id to select on (worker/src/panel/account.ts:564) | in the org export the grants, leases and handovers go with the org; frames and intents are keyed by machine, not by org, and are left to expire |
| House model usage and cost how many completions the shared house model account served on your org's behalf and what they cost in USD micros, per UTC window and per device, plus the short-lived back-off and single-use proof rows the rate limiter needs. The prompt you sent and the text that came back are NOT stored: the worker relays them and keeps only the counters. Nothing lands here while your org has a model key of its own — your key is always tried first, and a call it serves never reaches the house account. |
Cloudflare D1 (the control-plane database): house_ai_usage, house_ai_cooldown, house_ai_nonces | Cloudflare, Google | counters are kept per UTC window until you delete the org; there is no scheduled purge of them. The proof rows expire after five minutes and are swept by the next call, and a back-off row lasts about a minute | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Model call log a record of every model completion made on your org's behalf, whether served by your own key, a deployment key, or the shared house account: when it happened, who or what triggered it (a signed-in person, one of your computers, or an unattended background job), what it was for, which provider and model answered, whose bill it was, how many tokens moved, what it cost (house-served calls only — your own key's spend is between you and that provider), and whether it succeeded. The prompt you sent and the text that came back are NOT stored here either, same as house-model-usage above. |
Cloudflare D1 (the control-plane database): model_call_log | Cloudflare | swept opportunistically after about 90 days; there is no schema-level cap, and this is flagged as a follow-up rather than left unbounded | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Secrets you seal into the vault a model key or other credential you chose to store, encrypted at rest under a master key held as a Worker secret, plus the use-only grants that point at one. |
Cloudflare D1 (the control-plane database): org_model_keys, vault_items, resource_grants | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | withheld from the export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Which of your machines answers chat with its own CLI if you route chat through one of your own machines' claude or codex command-line tools instead of a stored API key: the machine's name, its id, which of the two tools, and when you last changed it. The tool's own login never leaves that machine and is not stored here. |
Cloudflare D1 (the control-plane database): org_machine_cli_settings | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) the OAuth access and refresh tokens for a third-party account you connect, encrypted at rest under their own master key (separate from the sealed-secret vault above), plus which scopes were shown to you and actually granted, and a log of which tool was invoked on your behalf and when. The one-time PKCE verifier used while a connection is being set up is also sealed here and deleted (consumed) within about 10 minutes either way. A deployment-wide OAuth CLIENT REGISTRATION (which app id this deployment uses to talk to a given provider) is shared across every org and is not your data — see the note under Retention.. |
Cloudflare D1 (the control-plane database): connector_grants, connector_auth_requests, connector_consents, connector_uses | Cloudflare, Google, Slack, GitHub, Notion, Linear, Asana, Dropbox, Box, Figma, Sentry, monday.com, Canva, HubSpot, Stripe | kept until you delete the org; there is no scheduled, time-based purge. connector_clients (the deployment-wide OAuth client registration, e.g. which Google Cloud project this deployment uses) is a SEPARATE table, shared by every org, and is not covered by this class or by any one org's deletion. | withheld from the export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Saved terminal grid layouts the named grid "views" you save on the Terminals page: the name you chose, which layout (single, two across, two stacked, 2x2, 3x3), which project it is filed under if any, and for each filled slot the control-link name, the tmux session name, whether it runs a shell, Claude Code or Codex, and the working directory you typed. It is an ARRANGEMENT, not a recording: no terminal output, no keystrokes and no command history are stored here. A view belongs to the person who saved it — a colleague in the same organisation cannot read it. |
Cloudflare D1 (the control-plane database): terminal_grid_views | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Notepad posts and shared files what you post to the shared notepad and what you distribute to a team: the text and metadata as rows, and the uploaded file itself as an object. |
Cloudflare D1 (the control-plane database): notepad_posts, distributions, distribution_outcomes, distribution_receipts; Cloudflare R2 (object storage): notepad/ | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export the rows go with the org. THE UPLOADED FILES DO NOT: the cascade deletes D1 rows only, so an object under the notepad prefix becomes unreachable rather than erased, and stays in the bucket until an operator removes it (worker/src/panel/account.ts:564) |
| Files attached to a Hawkeye chat message a file you attach to a message in Hawkeye chat (investor-demo build, 2026-09-10): the metadata as a row, the bytes as an object, and — for a text-shaped file only — a bounded extracted-text copy so a reply can quote what you attached. |
Cloudflare D1 (the control-plane database): chat_attachments; Cloudflare R2 (object storage): chat/ | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export both halves are real: the D1 row is swept by the deletion cascade (worker/src/panel/account.ts's ORG_DELETE_PLAN) and the R2 object is enumerated and deleted in the same deletion, then the prefix is re-listed to confirm nothing remains (account.ts's collectOrgObjectKeys/ deleteOrgObjects) |
| Files moved between machines the bytes of anything moved through the file-transfer endpoints, and the installer artifacts the download pages serve. |
Cloudflare R2 (object storage): xfer/; Cloudflare R2 (object storage): releases/ | Cloudflare | Not decided yet: how long a transferred object stays in the bucket. Nothing in this repository deletes one on a schedule and no lifecycle rule is recorded here; the download TICKET expires, the object does not. | withheld from the export not touched by org deletion — the cascade deletes D1 rows only. The ticket that reaches an object expires; the object itself remains until it is deleted through the transfer API or by an operator |
| Links between organisations the scoping rules you configure between two orgs and the record of who proposed and who approved each link. |
Cloudflare D1 (the control-plane database): org_links, cross_org_requests | Cloudflare | kept until you delete the org; there is no scheduled, time-based purge | in the org export deleted when the org is deleted — the table is named in the deletion cascade in worker/src/panel/account.ts |
| Billing events the plan-change events a payment provider reports for your org, and the checkout an owner starts (plan, price and the provider's checkout link). |
Cloudflare D1 (the control-plane database): billing_events; Cloudflare D1 (the control-plane database): billing_checkout_intents | Cloudflare, Stripe | kept until you delete the org; there is no scheduled, time-based purge | in the org export our rows go with the org. What the payment provider keeps for its own accounting is theirs and outlives the deletion |
| Browser-rendering jobs the queued page-rendering and bridge jobs the browser Worker runs: the action, the URL it was pointed at, the status and how long it took. |
Cloudflare D1 (the control-plane database): requests, jobs; Cloudflare D1 (the control-plane database): bridge_jobs; Cloudflare R2 (object storage): one random object name per capture | Cloudflare | Not decided yet: how long a rendering job row and its captured image stay. Nothing in this repository deletes either on a schedule. | withheld from the export not covered by org deletion — these rows are keyed by job, not by org |
| Rate and budget counters how many requests a caller has made this minute and this day, and how many browser-milliseconds the deployment has spent, as plain integers under a caller id and a date. |
Cloudflare KV (short-lived counters): rate:, budget: | Cloudflare | each counter is written with an expiry and Cloudflare drops it when that passes — the budget ledger's is 48 hours (worker/src/guards.ts:143) | withheld from the export expires on its own; there is nothing to delete by hand |
| Deployment state the operator's own switches and the schema-migration bookkeeping. No personal data and nothing belonging to a tenant. |
Cloudflare D1 (the control-plane database): settings, hawkeye_migration_state | Cloudflare | kept for the life of the deployment | withheld from the export not tenant data, so org deletion does not touch it |
| Error and performance telemetry when the control plane throws, the exception and its stack are sent to Sentry with the request method, the URL it happened on and the response status; timings are sent for a 10% sample of requests. Request bodies are switched off in the SDK, the user identity and IP are not attached, and the URL is stripped of any bearer credential before it leaves. |
a third party's systems: sentry | Cloudflare, Sentry | Not decided yet: how long Sentry keeps an error event for this project — set in the Sentry organisation, not in this repository, and not recorded here. | not ours to export deleting your org does not reach Sentry. An error event already sent expires under Sentry's own retention, whatever that is set to |
| Operator logs the console stream an operator reads to diagnose a failure: the method and path of a request that 500'd and the stack that caused it. Both wrangler configs enable Workers observability, so Cloudflare keeps that stream. |
Cloudflare Workers Logs (operator console stream): observability | Cloudflare | Not decided yet: how long Cloudflare keeps Workers Logs for this account. The product does not set the period and has not recorded it. | not ours to export deleting your org does not reach the log stream; entries age out under Cloudflare's retention |
| Receipts on your own machine every action a machine performed, written to a SQLite file next to the daemon on that machine. The panel reads it live over the machine's own outbound tunnel and keeps no copy. |
your own machine: ~/.hawkeye/receipts.db | nobody but you | nothing prunes or rotates it on its own. The daemon exposes a deliberate prune by age and a deliberate purge by org, and until one is called the store grows without bound (daemons/hawk_receipts.py:1255) | in the org export deleting the org asks every reachable machine to purge its receipts for that org, and reports per machine whether it answered (worker/src/panel/account.ts:793). A machine that is asleep is not purged, and the result says so rather than claiming it was |
What is NOT stored
- No credential for reaching your machines ever enters the database. The key the Worker presents to a machine is a Worker secret, held by the operator of the deployment. It is not a database row, it is not returned by any API, and it does not travel to a browser, to an agent, or into a model's context.
- Your agent channel history is not ours. Agent-to-agent messages live in a SQLite file on your own machine, next to the daemon. The panel reads them live, over your machine's own outbound tunnel, and keeps no copy. Delete that file and the history is gone — there is nothing on our side to also delete. The honest cost of that design: when the machine sleeps, the history is unavailable, and the product says "offline" rather than pretending it is empty.
- No advertising trackers, and no cross-site tracking. This is checkable
rather than promised, so here is the exact shape of it. Every page ships under a
default-src 'none'Content-Security-Policy with all styles inline, andconnect-src 'self'— the page cannot call anywhere but back here. One host is named as an exception inscript-src-elem:static.cloudflareinsights.com, Cloudflare's own Web Analytics beacon, which their edge can inject at the zone level outside this application's control. It is switched off today — read the page source and you will find no beacon, and no other off-site script could load even if one were added by mistake. We name it because you can read that header yourself, and finding an analytics host in a policy we told you to trust would be worse than saying so here. - No advertising, and no sale or sharing of personal data. There is no business here that would want it.
- Command output and file contents are not archived. When you run something on a machine, the result passes through the Worker to your screen to answer that request. The audit row records that you ran it and where, not the payload.
Error reporting — the one thing that leaves for a reason
There is no product analytics, no attribution and no campaign pixel. There is operational error reporting, and it is a real processor rather than a figure of speech, so it is stated exactly:
- Error and performance telemetry — when the control plane throws, the exception and its stack are sent to Sentry with the request method, the URL it happened on and the response status; timings are sent for a 10% sample of requests. Request bodies are switched off in the SDK, the user identity and IP are not attached, and the URL is stripped of any bearer credential before it leaves. Processed by Cloudflare and Sentry. Retention: Not decided yet: how long Sentry keeps an error event for this project — set in the Sentry organisation, not in this repository, and not recorded here. deleting your org does not reach Sentry. An error event already sent expires under Sentry's own retention, whatever that is set to.
- Operator logs — the console stream an operator reads to diagnose a failure: the method and path of a request that 500'd and the stack that caused it. Both wrangler configs enable Workers observability, so Cloudflare keeps that stream. Processed by Cloudflare. Retention: Not decided yet: how long Cloudflare keeps Workers Logs for this account. The product does not set the period and has not recorded it. deleting your org does not reach the log stream; entries age out under Cloudflare's retention.
Distinguishing the two matters more than the word "telemetry" does: service telemetry exists so an operator finds out that the product broke before you have to tell them. Nothing above measures what you looked at or builds a profile of you.
Where it lives
On Cloudflare: Workers for the code, D1 for the database, R2 for objects, KV for counters, and the platform's own log stream for the operator's console. Requests traverse Cloudflare's global network, and Cloudflare processes them as our infrastructure provider under its own terms. Your machines are yours — Hawkeye never dials in to them; they dial out.
Getting your data out
You can export a full copy of your org's rows — self-serve, no request needed: sign in
and use
/account/export
on the /account page. What the file contains, and what it deliberately does
not, comes from the same registry as the table above:
- In the file — Your account, Your organisation, Paired apps and runtimes, Invitations and access requests, Your machines, People you can route work to, Notification destinations, Notifications, The org stop switch and its record, The audit trail, The activity feed, Hosted cloud coding workspaces, Outbound control connections from your machines, Approval requests and their answers, Lead agent commands and autonomy settings, Geographic provenance rules for file transfers and vault access, Agent specs, conversations and workflows, Harness rules and templates, Hawkeye's memory of your conversations, Remote desktop grants and frames, House model usage and cost, Model call log, Which of your machines answers chat with its own CLI, Saved terminal grid layouts, Notepad posts and shared files, Files attached to a Hawkeye chat message, Links between organisations, Billing events, Receipts on your own machine.
- Deliberately withheld — Retired organisation identifier, Sign-ins, Credential verifiers, GitHub installation change fence, Cloud resource cleanup journal, Secrets you seal into the vault, Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...), Files moved between machines, Browser-rendering jobs, Rate and budget counters, Deployment state. A session id is a live login and a credential verifier is the lock itself; a file that contained either would be a credential you then email to yourself.
- Not ours to hand over — Platform-refuse confirmation code, Global refusal break-glass recovery code, Which OAuth app this deployment uses per connector, Error and performance telemetry, Operator logs. These sit with a processor under its own retention, and are named here rather than left out.
Getting it deleted
You can delete the org and its accounts yourself, through the two-step
/account/delete
(also on the /account page; it needs no sign-in to read). Deletion asks you to type the org's name back,
so it cannot happen by a single mis-click, and it asks every reachable machine to purge
its own receipts for that org. A member who is not an owner can close their own account
from the same page; the remaining personal records are erased within 30 days. You can also
ask by email, below.
Everything else in the table above is deleted when the org is deleted. These are the exceptions, each one for a stated reason:
- Retired organisation identifier — created atomically when the org is deleted and intentionally retained as a non-reusable namespace guard.
- Platform-refuse confirmation code — not org data and never swept by the org-deletion cascade in account.ts — it holds no org id, only a platform admin's own in-flight confirmation attempt.
- Global refusal break-glass recovery code — not org data and never swept by the org-deletion cascade in account.ts — it holds no org id, only a platform admin's own break-glass recovery material.
- The audit trail — your org's audit rows go with the org, but ONE deployment-level row survives it: a record, with no org id, that the deletion happened and who asked for it (worker/src/panel/account.ts:793). Keeping no evidence that we deleted something is not a record.
- GitHub installation change fence — not covered by org deletion — this is a deployment-level provider event fence with no org id, retained so deleting one tenant cannot reopen a stale consent callback.
- Which OAuth app this deployment uses per connector — not covered by org deletion — this is deployment-level configuration shared by every org, not one tenant's data.
- Cloud resource cleanup journal — it deliberately does not go with the organization row: already-authorized cleanup must finish after a controller restart, and the minimal final resource/cost/custody tombstone remains in the protected controller journal. No automatic purge period has been set.
- Remote desktop grants and frames — the grants, leases and handovers go with the org; frames and intents are keyed by machine, not by org, and are left to expire.
- Notepad posts and shared files — the rows go with the org. THE UPLOADED FILES DO NOT: the cascade deletes D1 rows only, so an object under the notepad prefix becomes unreachable rather than erased, and stays in the bucket until an operator removes it (worker/src/panel/account.ts:564).
- Files attached to a Hawkeye chat message — both halves are real: the D1 row is swept by the deletion cascade (worker/src/panel/account.ts's ORG_DELETE_PLAN) and the R2 object is enumerated and deleted in the same deletion, then the prefix is re-listed to confirm nothing remains (account.ts's collectOrgObjectKeys/ deleteOrgObjects).
- Files moved between machines — not touched by org deletion — the cascade deletes D1 rows only. The ticket that reaches an object expires; the object itself remains until it is deleted through the transfer API or by an operator.
- Billing events — our rows go with the org. What the payment provider keeps for its own accounting is theirs and outlives the deletion.
- Browser-rendering jobs — not covered by org deletion — these rows are keyed by job, not by org.
- Rate and budget counters — expires on its own; there is nothing to delete by hand.
- Deployment state — not tenant data, so org deletion does not touch it.
- Error and performance telemetry — deleting your org does not reach Sentry. An error event already sent expires under Sentry's own retention, whatever that is set to.
- Operator logs — deleting your org does not reach the log stream; entries age out under Cloudflare's retention.
- Receipts on your own machine — deleting the org asks every reachable machine to purge its receipts for that org, and reports per machine whether it answered (worker/src/panel/account.ts:793). A machine that is asleep is not purged, and the result says so rather than claiming it was.
If a self-serve route is not enough — an access request, or a question about something above — write to contact@transition2.ai and we aim to reply within 2 business days.
Sub-processors
Everyone outside this deployment that data can reach, why, and what actually gets to them. A processor marked not switched on for this deployment is wired in the code but has no credentials configured, so nothing reaches it today; it is listed anyway, because "we will tell you when we turn it on" is a promise a page cannot keep.
| Who | What for | What reaches them | Which data classes | Region |
|---|---|---|---|---|
| Cloudflare sub-processor |
runs the control plane and stores everything it keeps | every request to this site, and every row, object and counter the product writes: the D1 database, the R2 object store, the KV counters, and the Workers Logs the platform keeps for the operator | Your account, Your organisation, Retired organisation identifier, Sign-ins, Paired apps and runtimes, Credential verifiers, Invitations and access requests, Your machines, People you can route work to, Notification destinations, Notifications, The org stop switch and its record, Platform-refuse confirmation code, Global refusal break-glass recovery code, The audit trail, The activity feed, Hosted cloud coding workspaces, GitHub installation change fence, Which OAuth app this deployment uses per connector, Cloud resource cleanup journal, Outbound control connections from your machines, Approval requests and their answers, Lead agent commands and autonomy settings, Geographic provenance rules for file transfers and vault access, Agent specs, conversations and workflows, Harness rules and templates, Hawkeye's memory of your conversations, Remote desktop grants and frames, House model usage and cost, Model call log, Secrets you seal into the vault, Which of your machines answers chat with its own CLI, Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...), Saved terminal grid layouts, Notepad posts and shared files, Files attached to a Hawkeye chat message, Files moved between machines, Links between organisations, Billing events, Browser-rendering jobs, Rate and budget counters, Deployment state, Error and performance telemetry, Operator logs | Not decided yet: the D1 region this deployment's database is pinned to, so the answer to “where does my data physically sit” is a place and not a network. |
| Sentry sub-processor |
operational error and performance reporting for the control plane | an unhandled exception and its stack, the request method, the URL it happened on with any bearer credential removed first, the response status, and timings for a 10% sample of requests | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...), Error and performance telemetry | United States (the deployed DSN posts to Sentry's us ingest host) |
| Stripe service you connect · not switched on for this deployment |
checkout and the billing portal, when a deployment configures them | the plan you chose and the identifiers Stripe needs to bill it. Card numbers are entered on Stripe's own pages and never reach Hawkeye | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...), Billing events | Not decided yet: the region Stripe processes this account in. |
| Resend sub-processor · not switched on for this deployment |
sends the product's transactional email | the destination address and the body of the message being sent to it — an invitation, a password-reset link, or a notification you asked for | Invitations and access requests, Notification destinations, Notifications, Platform-refuse confirmation code | Not decided yet: the region Resend delivers from for this account. |
| Twilio sub-processor · not switched on for this deployment |
sends SMS to a phone number you add as a notification channel | the phone number you typed in and the text of the message | Notification destinations, Notifications | Not decided yet: the region Twilio delivers from for this account. |
| Slack service you connect · not switched on for this deployment |
posts notifications and approval cards into a workspace you connect, and reads the reply (the org-level bot connection); separately, if YOU personally connect your own Slack account as a connector, whatever Slack tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Slack MCP session | the notification or approval text the product sends, the workspace and channel it goes to, and the Slack user id of whoever answers; for a personally-connected account, whatever that Slack tool call sends and returns (e.g. reading or posting a message) | Notification destinations, Notifications, Approval requests and their answers, Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Slack processes your workspace in. |
| Google service you connect · not switched on for this deployment |
Sign in with Google, Firebase Cloud Messaging for push notifications to a paired phone, and — only when your org has no model key of its own — Vertex AI serving the house model fallback. Separately, if you connect your own Google Drive, Calendar or Gmail account as a connector, whatever tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Google account, over Google's own official remote MCP servers (Gmail is configured but not yet usable — see the connector's own note on the Connectors page) | for sign-in, the OAuth exchange and the account email Google returns; for push, the notification title and body and the device token it is delivered to; for the house model, the prompt text a device sent and the completion Vertex returns — relayed, never stored by us (worker/src/panel/houseai.ts). Separately, when your org connects its OWN Google Gemini key under Model keys, the message you sent and the reply go to the Gemini API on that key and bill to your own quota, never to the house account (worker/src/panel/modelkeys.ts). For a connected Drive/Calendar/Gmail connector, whatever that tool call sends and returns (e.g. reading a file or an event) | Notifications, Agent specs, conversations and workflows, Hawkeye's memory of your conversations, House model usage and cost, Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Google processes these requests in. |
| Anthropic service you connect · not switched on for this deployment |
answering Hawkeye's own replies on YOUR Anthropic key, when your org has connected one under Model keys | the message you sent, the recent excerpts of that conversation Hawkeye quotes as context, and the reply it returns — relayed, never stored by us beyond the conversation you can already see (worker/src/panel/modelkeys.ts's orgCompletion) | Agent specs, conversations and workflows, Hawkeye's memory of your conversations | Not decided yet: the region Anthropic processes these requests in. |
| OpenAI service you connect · not switched on for this deployment |
answering Hawkeye's own replies on YOUR OpenAI key, when your org has connected one under Model keys | the message you sent, the recent excerpts of that conversation Hawkeye quotes as context, and the reply it returns — relayed, never stored by us beyond the conversation you can already see (worker/src/panel/modelkeys.ts's orgCompletion) | Agent specs, conversations and workflows, Hawkeye's memory of your conversations | Not decided yet: the region OpenAI processes these requests in. |
| OpenRouter service you connect · not switched on for this deployment |
answering Hawkeye's own replies on YOUR OpenRouter key, when your org has connected one under Model keys | the message you sent, the recent excerpts of that conversation Hawkeye quotes as context, and the reply it returns. OpenRouter is a ROUTER: it forwards the same content to whichever upstream model provider serves the model id you configured, so that provider receives it too (worker/src/panel/modelkeys.ts's orgCompletion) | Agent specs, conversations and workflows, Hawkeye's memory of your conversations | Not decided yet: the region OpenRouter and its upstreams process these requests in. |
| GitHub service you connect · not switched on for this deployment |
Sign in with GitHub; separately, if you connect your own GitHub account as a connector, whatever GitHub MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own GitHub account, over GitHub's official remote MCP server | for sign-in, the OAuth exchange and the account email GitHub returns; for a connected connector, whatever that tool call sends and returns (e.g. reading or commenting on an issue) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region GitHub processes these requests in. |
| Notion service you connect · not switched on for this deployment |
if you connect your own Notion account as a connector, whatever Notion MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Notion workspace, over Notion's official remote MCP server | whatever that tool call sends and returns (e.g. reading or editing a page) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Notion processes these requests in. |
| Linear service you connect · not switched on for this deployment |
if you connect your own Linear account as a connector, whatever Linear MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Linear workspace, over Linear's official remote MCP server | whatever that tool call sends and returns (e.g. reading or creating an issue) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Linear processes these requests in. |
| Asana service you connect · not switched on for this deployment |
if you connect your own Asana account as a connector, whatever Asana MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Asana workspace, over Asana's official remote MCP server | whatever that tool call sends and returns (e.g. reading or creating a task) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Asana processes these requests in. |
| Dropbox service you connect · not switched on for this deployment |
if you connect your own Dropbox account as a connector, whatever Dropbox MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Dropbox account, over Dropbox's official remote MCP server | whatever that tool call sends and returns (e.g. listing or reading a file) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Dropbox processes these requests in. |
| Box service you connect · not switched on for this deployment |
if you connect your own Box account as a connector, whatever Box MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Box account, over Box's official remote MCP server | whatever that tool call sends and returns (e.g. listing or reading a file) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Box processes these requests in. |
| Figma service you connect · not switched on for this deployment |
if you connect your own Figma account as a connector, whatever Figma MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Figma account, over Figma's official remote MCP server | whatever that tool call sends and returns (e.g. reading a file or a comment) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Figma processes these requests in. |
| HubSpot service you connect · not switched on for this deployment |
if you connect your own HubSpot account as a connector, whatever HubSpot MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own HubSpot portal, over HubSpot's official remote MCP server | whatever that tool call sends and returns (e.g. reading or updating a contact) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region HubSpot processes these requests in. |
| monday.com service you connect · not switched on for this deployment |
if you connect your own monday.com account as a connector, whatever monday MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own monday.com account, over monday's official remote MCP server | whatever that tool call sends and returns (e.g. reading or updating a board item) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region monday.com processes these requests in. |
| Canva service you connect · not switched on for this deployment |
if you connect your own Canva account as a connector, whatever Canva MCP tool Hawkeye's chat invokes on your behalf (connectorTools.ts) runs against your own Canva account, over Canva's official remote MCP server | whatever that tool call sends and returns (e.g. reading or creating a design) | Third-party connectors you connect (Google Drive, Slack, GitHub, Notion, Linear, ...) | Not decided yet: the region Canva processes these requests in. |
| @simplewebauthn/server local code |
cryptographically verifies a passkey's registration and login ceremonies — the WebAuthn spec's own attestation/assertion checks, run in-process rather than hand-rolled | nothing over a network. It is a pure computation library: it decodes and verifies bytes this Worker already has (a challenge it minted itself, and the browser's signed response) using Web Crypto, and it makes no outbound call of its own — confirmed by grep over its installed source for any host or fetch call, and there is none | — | not applicable — it never leaves this Worker's own process |
| HawkNet mesh control plane sub-processor |
mints a one-off NetBird mesh setup key so a Hawkeye box can join the HawkNet mesh automatically, without an operator hand-minting one, scoped into that org's own isolated mesh group and policy (created on first use) so it can only reach that org's own peers (worker/src/hawknetenroll.ts, TASK-HAWKNET Phase A + org isolation) | the requesting device's Hawkeye org identifier and device name (its SPIFFE id), sent only when that device presents its own already-issued, root-signed Hawkeye credential to /v1/id/device/hawknet-enroll. Returns a real, one-off WireGuard mesh join credential, valid 24h and usable exactly once | — | DigitalOcean -- operated by us, not a separate company's own infrastructure |
A new processor cannot be enabled without a registry entry: the release check reads every third-party hostname, every imported package and the deployed configuration out of the source, and fails when one of them is missing from the table above. That is the change-notice process, mechanised rather than promised.
Who is accountable, and where
The data controller is Transition 2 Consulting Inc. of Victoria, British Columbia, Canada V9B 4J5, operating under the laws of British Columbia, Canada. A privacy complaint that reaches the applicable regulator would go to the Office of the Privacy Commissioner of Canada. For export, deletion or access requests beyond the self-serve tools above, write to contact@transition2.ai — we aim to respond within 2 business days.
Retention
Stated exactly, not rounded up, per class, in the table above. The shape of it: sessions, tickets and counters carry their own expiry and are refused or dropped past it; everything else is kept until you delete the org. There is no automatic, time-based purge for the rest, and where nobody has set a period this page says so below rather than implying one.
TODO — not filled in yet
These are deliberately blank rather than invented. Nothing below is a placeholder standing in for a real answer; where a fact is missing, it is missing.
- Hawkeye's memory of your conversations — how long an extracted memory is kept when nothing ever retrieves it. Today it is kept until you delete the org, like everything else here, and there is no scheduled purge.
- Files moved between machines — how long a transferred object stays in the bucket. Nothing in this repository deletes one on a schedule and no lifecycle rule is recorded here; the download TICKET expires, the object does not.
- Browser-rendering jobs — how long a rendering job row and its captured image stay. Nothing in this repository deletes either on a schedule.
- Error and performance telemetry — how long Sentry keeps an error event for this project — set in the Sentry organisation, not in this repository, and not recorded here.
- Operator logs — how long Cloudflare keeps Workers Logs for this account. The product does not set the period and has not recorded it.
- Cloudflare — the D1 region this deployment's database is pinned to, so the answer to “where does my data physically sit” is a place and not a network.
- Cloudflare — how long Cloudflare keeps the Workers Logs this deployment enables (observability is on in both wrangler configs); the product does not set that period and has not recorded it.
- Sentry — the retention Sentry is configured to apply to this project; it is set in the Sentry organisation rather than in this repository, and has not been recorded here.
- Stripe — the region Stripe processes this account in.
- Stripe — how long Stripe keeps payment records under its own accounting obligations.
- Resend — the region Resend delivers from for this account.
- Resend — how long Resend keeps a delivered message and its logs.
- Twilio — the region Twilio delivers from for this account.
- Twilio — how long Twilio keeps a delivered message and its logs.
- Slack — the region Slack processes your workspace in.
- Slack — how long a message stays in your workspace — that is your Slack retention setting, not ours.
- Google — the region Google processes these requests in.
- Google — how long Google keeps an OAuth or push delivery record.
- Anthropic — the region Anthropic processes these requests in.
- Anthropic — how long Anthropic keeps an API request record.
- OpenAI — the region OpenAI processes these requests in.
- OpenAI — how long OpenAI keeps an API request record.
- OpenRouter — the region OpenRouter and its upstreams process these requests in.
- OpenRouter — how long OpenRouter keeps an API request record.
- GitHub — the region GitHub processes these requests in.
- GitHub — how long GitHub keeps an OAuth authorisation record.
- Notion — the region Notion processes these requests in.
- Notion — how long Notion keeps an API request record.
- Linear — the region Linear processes these requests in.
- Linear — how long Linear keeps an API request record.
- Asana — the region Asana processes these requests in.
- Asana — how long Asana keeps an API request record.
- Dropbox — the region Dropbox processes these requests in.
- Dropbox — how long Dropbox keeps an API request record.
- Box — the region Box processes these requests in.
- Box — how long Box keeps an API request record.
- Figma — the region Figma processes these requests in.
- Figma — how long Figma keeps an API request record.
- HubSpot — the region HubSpot processes these requests in.
- HubSpot — how long HubSpot keeps an API request record.
- monday.com — the region monday.com processes these requests in.
- monday.com — how long monday.com keeps an API request record.
- Canva — the region Canva processes these requests in.
- Canva — how long Canva keeps an API request record.
- Every class above — the legal basis for each class. The controller is Canadian, where PIPEDA asks for consent rather than naming a lawful basis; whether the GDPR also applies to this deployment, and which basis each class would then sit under, has not been decided by anyone qualified to decide it.
This page describes the deployment you are reading it on. If you run Hawkeye yourself, you are the operator and these answers are yours to give.