Skip to content

Data, Privacy & Safety ​

JobCtrl stores your working data on your computer. Network access happens only when a feature you start—or a schedule you explicitly enable—needs a configured external service.

This page owns the data inventory and responsible-use boundaries. For the controls that enforce risky actions, read Security. Feature settings live in Discovery and Apply; shared providers, precedence, and spend controls live in Configuration. For a plain-language overview, read Local-first Job Search Automation.

Privacy Quick Answer ​

QuestionAnswer
Do I need a hosted backend or a JobCtrl account?✕ No. App, API, worker, database, and files run locally.
Are the database and generated files stored locally?✓ Yes, by default. They live under JOBCTRL_DIR (normally ~/.jobctrl/).
Does JobCtrl call AI models or other providers automatically?◐ Only when you use a configured feature. Generation and opted-in research call providers during runs you start or schedules you explicitly enable.
Does Discovery make network requests?✓ Yes—that is how it searches configured job sources and, for AI-assisted steps, communicates with the model providers you selected. Requests occur during runs you start or schedules you explicitly enable.
Is product telemetry enabled by default?✕ No. Langfuse requires configuration; LANGFUSE_DISABLE=1 overrides it.
Does this documentation site use analytics?◐ Only after you accept. The optional Google Analytics tag stays unloaded until you choose Accept analytics; declining keeps the documentation fully available.
Does Discovery use my browser profile?◐ When the selected paired extension is connected. Discovery and Enrich prefer its live profile for bounded HTTP/API tasks and temporary inactive tabs. Without it, they use guarded public HTTP or anonymous managed Playwright. They never copy or separately launch your profile, and a fetch failure does not change transport.
Does application-submission browser automation run continuously?✕ No. It starts only through apply/dry-run work you initiate or a standing loop you explicitly enable.
Does JobCtrl submit applications or send employer-facing email by default?✕ No. Browser submission and Gmail application sending are explicit guarded actions.
Does browsing Interviews call a model?✕ No. The installed public catalog is local. Job-specific generation is a separate explicit provider-backed action.
Does Outreach send messages automatically?✕ No. Drafts end at copy/export; send logs are user attestations.
Does Plate PDF export upload or register my edited resume?✕ No. The browser renders the currently visible Plate document into a download; it does not call a generation provider, save the edits, or register a JobCtrl artifact.

Local-first does not mean offline. Discovery fetches sources, generation calls models, and live apply contacts an employer only when you use those features.

Local product boundary Your workspace stays local; configured features cross the boundary only when used. A user action or an explicitly enabled schedule opens the boundary only for the feature being used.

Data-boundary summary: JobCtrl processes, SQLite data, and workspace files stay on your computer. When you use a configured feature, or explicitly enable its schedule or standing loop, that feature may send its relevant data to job sources, selected model providers, connected services, or explicitly configured telemetry. Local-first does not mean offline.

What can start a network-using feature?Each trigger invokes only its configured feature.
You start or use a featureA run, browser action, provider call, or interactive lookup.
You enable automationAn explicit schedule or standing loop invokes its configured feature.
Stays on this computerLocal workspace
  • Local processesThe web app, loopback API, Temporal, and automation worker run on your computer.
  • Canonical dataProfile, jobs, Discovery controls, events, and projections remain in the local SQLite workspace.
  • Workspace filesconfig.json, generated materials, backups, and browser/apply state remain under JOBCTRL_DIR; source-development logs remain in the checkout's .dev directory.
Request gate
  • Feature in use
  • Service configured
  • Data for that feature
May receive feature dataConfigured services
  • Job sources and pagesDiscovery and enrichment send search terms, URLs, and page or API requests to configured sources.
  • Model providersSelected providers receive posting text, relevant profile evidence, or generated text for that feature.
  • Connected actionsEmployer pages, Gmail, Google Maps, or a CAPTCHA provider receive data only in the flow you use.
  • Optional telemetryMetadata-only spans leave the machine only when Langfuse and OpenTelemetry are explicitly configured.

Local-first does not mean offline. Discovery fetches sources, generation calls models, and live apply contacts an employer when you use those features.

Documentation Site Analytics ​

The documentation at https://jobctrl.dev uses optional Google Analytics 4 measurement only after consent. On a first visit, the cookie banner offers Decline analytics and Accept analytics without blocking the guide. Before acceptance, the site does not load or contact Google Analytics.

The consent choice is stored in browser local storage under the versioned key jobctrl-docs-analytics-consent-v1. The footer's Cookie settings control reopens the choice at any time. Declining or withdrawing consent stops new page views, removes the Google tag from the page, and attempts to delete the documentation site's _ga, _gid, and _gat cookies. Withdrawing reloads the current documentation page so the previously loaded third-party runtime is no longer present. It cannot delete measurement data Google already received.

After acceptance, the site loads Google tag G-KB495KG6MS. Page views contain the documentation path and page title, without URL query strings or fragments. Google may also receive the referrer, browser/device details, interaction data, and an IP address used for geolocation before it is discarded. JobCtrl disables Google Signals plus advertising and personalization signals, and configures host-only Google Analytics cookies that are not sent to demo.jobctrl.dev and expire within six months. A denial or withdrawal in one documentation tab reloads other open documentation tabs so none keep a stale consented tag. Google's handling of that data is described in Safeguarding your data.

The data controller for this documentation measurement is Eloi Barti, acting as an individual. For privacy questions, contact [email protected]. This hosted documentation measurement is separate from JobCtrl's local product telemetry and from the public demo measurement described below.

Public Demo ​

The hosted synthetic demo is separate from the local product described above. It can only be used after accepting analytics cookies for JobCtrl's bounded first-party demo measurement and Google Analytics. Declining returns to https://jobctrl.dev; opening the demo again shows the choice again. The demo does not initialize its browser-local workspace or load the Google tag until the consent service confirms acceptance. The v2 consent contract replaces the earlier first-party-only choice, so existing visitors are asked again once.

The data controller for the public demo is Eloi Barti, acting as an individual. For privacy questions, contact [email protected].

After acceptance, Cloudflare sets a versioned consent cookie plus random HttpOnly visitor and session identifiers. JobCtrl's persistent cookies expire within six months, the session cookie at the end of the browser session, and raw demo events and non-linkable operational counters expire within 90 days. Those first-party events use closed route/action/result categories: they exclude names, contact details, profile or resume text, job/company content, URLs, searches, comments, local paths, raw errors, and demo entity/workspace identifiers. IP addresses may be used transiently by Cloudflare rate limiting but are not written to D1 or application logs.

The accepted page also loads Google tag G-6MJGD17JN0. Google Analytics may set _ga cookies scoped to the demo host for up to six months and receive standard web-measurement data such as page location, referrer, browser/device details, interaction data, and an IP address used for geolocation before it is discarded. JobCtrl disables Google Signals plus advertising and personalization signals in the tag configuration. Google's handling of that data is described in Safeguarding your data.

The demo contains synthetic data. Do not enter personal data, credentials, or secrets. Post-accept withdrawal and immediate visitor-event deletion are not yet available in this MVP; retained data and cookies expire on the schedules above. The consent screen links to this disclosure before entry.

The demo access, consent withdrawal, and visitor erasure proposal is a future design for #885. It is PROPOSED, awaits owner decisions, and does not change the current consent gate, retention, or deletion behavior described above.

After entry, the compact Demo guide links to seeded scoring evidence, tailored-material review, Apply Review/dry-run, and run history. Every shortcut and action is simulated; it does not contact employers, send messages, or make external changes. Reset synthetic demo data asks for confirmation, then replaces the browser-local workspace with the original examples. When a deployment changes the versioned synthetic seed, the next demo load performs the same replacement automatically: it rotates the workspace identity, clears pending simulated actions, and deletes generated demo blobs. This seed refresh does not change the separate consent cookie or telemetry-retention schedule.

Local Data ​

Default workspace:

text
~/.jobctrl/

Unless a row says otherwise, every path below is relative to JOBCTRL_DIR (normally ~/.jobctrl/).

PathContents
jobctrl.db plus -wal / -shmProfile, jobs, discovery settings, events, projections, artifact metadata, review drafts, contacts, private offer terms/decisions and sources, and workflows. Treat all three files as one database.
temporal.db plus -wal / -shmBundled-runtime Temporal state. During a native bundled update or rollback, it is hash-snapshotted and restored only together with jobctrl.db; never restore just one member of that pair.
config.jsonNon-secret Settings values: general controls, provider configuration metadata, preferred model IDs, compensation source policy, and browser-adoption metadata. No API keys or feed contents.
.envLegacy/plaintext provider credentials used by remaining compatibility paths. Not encrypted at rest.
codex_home/Stable JobCtrl-owned Codex CLI state. auth.json is outside the prompt-readable workspace/ subtree.
claude_home/, provider-packs/, provider-runtime/Isolated or separately acquired provider runtime state.
tailored_resumes/, cover_letters/Generated text, HTML, and PDF artifacts.
logs/, apply-workers/, chrome-workers/Logs and local browser/apply state, including CAPTCHA usage metadata when applicable.
browser-profiles/Consented copied profiles retained for separate compatibility capabilities. Integrated DiscoverWorkflow never reads or launches them. Non-secret adoption metadata lives in config.json.
extension-capability-token, extension-discovery-installation-idPrivate local browser-extension pairing secret and the extension installation selected for Discovery. Discovery bridge task bodies and results are memory-only and are not stored beside them.
backups/Database snapshots: pair-<id>/ directories written by the installed launcher's backup, update, and rollback; jobctrl-<timestamp>.db files from a source checkout's backup; and job-data purge recovery bundles. See Back Up And Restore.
gmail/Gmail OAuth client and token files.
Baseline/legacy resume filesresume.txt, resume.pdf, and older local style/template files.

PDFs created with a Plate editor's Export PDF control are ordinary browser downloads, so their destination is the download location selected by the browser or operating system rather than JOBCTRL_DIR. JobCtrl does not register that copy as a material artifact or use it to replace an accepted generation.

The development launcher writes PIDs and logs under the checkout's .dev/ directory; treat those logs as sensitive too.

Back Up And Restore ​

bash
jobctrl backup

The installed command snapshots jobctrl.db and temporal.db together into a new backups/pair-<id>/ directory. If JobCtrl is running, it stops for the snapshot and starts again afterward. --output takes an absolute directory. The two files are one restore unit: never restore just one of them. The launcher has no restore command for these pairs; updates and rollbacks write and restore their own, as described in Update, Roll Back, Or Remove JobCtrl.

In a source checkout, uv --project workers/automation run jobctrl backup writes one consistent copy of jobctrl.db to backups/jobctrl-<timestamp>.db with SQLite VACUUM INTO. It is safe while the app runs and never deletes anything; --output takes a file or directory. To restore it, stop corepack pnpm dev, clear the stale WAL sidecars, and copy the backup over the live database:

bash
rm -f ~/.jobctrl/jobctrl.db-wal ~/.jobctrl/jobctrl.db-shm
cp ~/.jobctrl/backups/jobctrl-<timestamp>.db ~/.jobctrl/jobctrl.db

Always restore the whole file; never hand-import individual tables. Read-model projection watermarks only move forward, so if a database is ever rebuilt piecemeal, delete the Python and TypeScript operations-projection watermarks to rebuild projections:

bash
sqlite3 ~/.jobctrl/jobctrl.db \
  "DELETE FROM event_watermarks WHERE projection_name LIKE '%operations_projections%';"

Credentials Outside The Workspace ​

The macOS credential panel guides Codex, Claude, and Google setup. Codex uses the stable, separate $JOBCTRL_DIR/codex_home. Codex-backed work requires an authenticated Codex CLI first. If its auth.json is absent, setup or generation may copy valid authentication once from the effective normal Codex CLI home. JobCtrl never overwrites existing isolated auth or changes the normal home. Only auth.json is copied; personal Codex settings, instructions, skills, chats and logs are not imported. JobCtrl does not save Codex generation chats, and each provider client removes its temporary databases and logs when it closes. Existing provider files from earlier versions are preserved. The auth file remains outside codex_home/workspace/, the only JobCtrl Codex subtree available to prompt-driven reads. Anthropic and Gemini API keys use the native OS credential store; cloud activation flags and non-secret identifiers belong in config.json. AWS, Google, and Azure credential files remain in their vendor stores. After environment-file loading, Python loads native credentials at startup only when the corresponding environment value is missing or empty. Any non-empty inherited value wins. Restart JobCtrl after saving or removing a value.

The adapters use macOS Keychain, Windows Credential Manager, or Linux Secret Service. The panel returns status, never stored values. Unknown (inspection_failed) means the store could not be inspected, not that a credential is absent. Unlock or restore access to the native store and retry. See Configuration for legacy plaintext migration and its scope; migration does not erase old backups or vendor-managed auth files.

Protected by default

The normal workspace is outside the repository. .gitignore and the release privacy scan add safeguards. From a source checkout, use corepack pnpm qa:seed for anything you intend to share.

Contacts And Outreach ​

Contact values and notes stay in canonical local tables. Events and broad projections carry only IDs, kinds, counts, timestamps, and provenance metadata.

Contact research is supervised:

  1. you provide or opt into a permitted source;
  2. JobCtrl records the source attempt and proposes candidates;
  3. you confirm a candidate before it becomes a contact.

Draft bodies, gate results, and claim provenance are stored locally. When you request a generated or edited outreach draft, its relevant profile/contact facts and actual text go to the configured provider for drafting and review. Offer communication additionally sends the confirmed offer terms, source quotations, decision attestation and existing compensation evidence. Recording or reading terms/decisions alone makes no provider request. Private offer ledger payloads stay out of general event-stream and activity/audit responses. An approved draft can be copied/exported; JobCtrl has no outreach send transport. Logging a send records something you did. Follow-ups are reminders and never act automatically.

Interview Guidance, Preparation, And Notes ​

The installed question catalog contains public editorial research and synthetic examples. Its source ledger records whether guidance comes directly from an interview source, extrapolates leadership practice, or is editorial synthesis, and how much of each source was read. Attribution does not imply author endorsement or prove any personal claim. The catalog and its criteria remain a research draft; they do not establish hiring outcomes or validated grading.

Browsing the library needs no job, database, live worker, or provider call. Opening an external source link uses the browser's normal network access. Explicit job preparation sends only the selected cards and bounded relevant profile/job context to the configured model under the existing provider and spend controls. It does not generate a personalized answer for every card.

Accepted prep, its retained input excerpts, generation history, and revisioned per-question notes are private local job data. Notes are user edits and new recollections remain unverified statements; saving or generating preparation does not promote them into Profile, change fit scores or Discovery intent, replace approved resumes, or authorize Apply. Question, job, generation, and revision IDs may enter events; answer, note, profile, and excerpt text may not. The local retention and job-deletion boundary applies to these records. Keep notes and prep out of screenshots, public issues, PRs, and shared logs.

The compensation question C07 asks for the employer's budgeted range first. Public negotiation guidance is separate from your private compensation preferences. It must not disclose an inferred minimum or treat a deliberate user-chosen exception as a competency failure. The retired C08 ID remains reserved: logistics and authorization are your declared checklist facts.

Reusable preparation without a job, typed rehearsal, calibrated assessment, and live interview assistance are not shipped by this integration. See Interview preparation.

External Services ​

ServiceWhen usedData involved
LLM providersScoring, employer analysis, materials, contact extraction, stored interview prep, offer communication drafts, opted-in Required-bullet coachingPosting text, relevant profile evidence, generated text, or opted-in fetched page text. Offer communication includes confirmed actual terms and quotations, the decision attestation and recorded compensation evidence; saving or reading an offer does not call a provider. Required-bullet coaching sends selected saved Required bullets, their role/company context and matching achievement evidence to your configured provider. Candidate interpretation and target-role suggestions send minimized saved profile sources to the configured Profile provider after spend preflight. Every suggestion cites source IDs and verbatim spans and needs your confirmation; provider or budget failure reports unavailable without a lexical substitute.
Job boards, ATS APIs, posting pagesDiscovery and Enrich prefer the connected paired extension; otherwise acquisition uses guarded public HTTP or anonymous PlaywrightBoth modes send search terms, URLs, and page/API requests. Connected Chrome may also send cookies or session state belonging to that site; its cookie values are never copied into worker tasks or results, and its user-agent string is returned as transport metadata. Anonymous acquisition uses no personal Chrome profile or ambient netrc credentials.
Apply model and browserApply/dry-run work you start, or a standing loop you enableThe reviewed application URL and the page content observed during the transport-locked inspection. Profile fields, job-description prose, resume and cover-letter text, local artifact paths, and upload authority are excluded; see Apply.
Salary data sourcesAt the end of a Discover run, only for benchmark slices that are missing or past their seven-day freshness window; Levels.fyi or Glassdoor only when their Settings policy permitsRequests for public benchmark data from Euro Top Tech, ECB exchange rates when a currency conversion is needed, and Eurostat price levels when a slice has no direct benchmark. Levels.fyi public-page URLs name the role and location being benchmarked.
GmailAuthenticated verification, bounded outcome feedback, or an approved email applicationScoped queries/evidence or the exact approved recipient/attachment.
Google MapsProfile location autocomplete with a configured keyAddress text typed into the location field.
CAPTCHA providerSupported widget during an apply run you explicitly start or a standing loop you enable, with a configured solverSite key and page URL through the owned local tool.
Langfuse/OpenTelemetryExplicitly configured telemetryMetadata-only LLM, workflow, and JSON-RPC spans: provider/model, operation/stage, outcome, token counts, and safe sizes.

When using the connected paired extension, Discovery and Enrich capture HTML and text from your current Chrome session. If you are signed in, those snapshots can include account-personalized content beyond the posting, such as greetings or job-match panels. Anonymous acquisition captures public HTTP responses or pages rendered in a managed browser without adopting your personal Chrome profile. Anonymous JobStreaming sessions do not read NETRC or ~/.netrc; provider-supplied protocol headers and cookies still work. Configured proxies that would route an anonymous provider request are rejected, including on redirects, because their destination DNS cannot be pinned safely.

In either mode the worker processes the acquired content. Extracted posting text can be persisted locally, and page HTML or posting text can be sent to configured LLM providers for extraction and later pipeline stages. Keeping broker tasks in memory does not prevent this downstream persistence or LLM processing.

Review Security → What Leaves Your Machine before enabling a provider.

Responsible Use Boundaries ​

  • Employer actions are irreversible. Rehearse with dry-run, review current materials and field mappings, complete browser final submission manually, and keep applyApprovalRequired enabled for live claims.
  • Email applications are live submissions. They require a recorded recipient/attachment candidate and matching Apply Review approval.
  • Source access has terms. Enable only job boards, feeds, and public pages you are allowed to query. JobCtrl does not authorize access for you.
  • CAPTCHA and login flows fail closed. Unsupported challenges, identity or biometric checks, payment/bank prompts, and missing credentials require human handling.
  • The API is loopback software. Binding it beyond 127.0.0.1 or tunneling it can expose private profile, job, artifact, and credential-adjacent data.
  • LLM spend is real. dailyBudgetUsd limits new JobCtrl workflows based on a local estimate; keep provider-side billing controls too.
  • Interview prep is stored pre-interview material. It is not live assistance and has no microphone, transcript, stream, or real-time answer surface.

Auto-Apply Safety ​

The detailed enforcement model lives in Security. The user-facing guarantees are:

  • live claims require a current bound approval by default;
  • system-browser apply is disabled until you explicitly enable and adopt the auto-apply-browser capability;
  • Settings may detect a supported browser for display, but detection is read-only and exposes only an ID/label pair. JobCtrl does not launch, copy, persist, or adopt it until you explicitly select and enable that capability;
  • dry-run has a browser-layer network/submission guard;
  • model-driven browser sessions are transport-locked and final browser submit remains manual;
  • the owned email sender checkpoints submit intent immediately before sending, so ambiguous crashes do not cause blind retries;
  • email-only applications require the same reviewed recipient/attachment binding; and
  • failed replacements never delete the last accepted materials.

Applying is irreversible

Start narrowly. Once an application or email is sent, JobCtrl cannot undo it.

Scoring Safety ​

Scores are applicant-side triage aids. They are not employer-side screening or hiring decisions. Using them to rank people would require separate legal, bias-audit, validation, notice, and human-review controls.

LLM Spend Ceiling ​

dailyBudgetUsd defaults to 25; 0 means unlimited. A preflight blocks the next spendful workflow after the local daily estimate reaches the ceiling. It does not interrupt a call already in flight and is not provider billing truth. Current estimated spend appears on the health surface.

Telemetry ​

Langfuse export is off unless configured. When enabled, it exports metadata-only LLM, workflow, and JSON-RPC spans. Raw prompts, messages, job/profile/material text, completions, credentials, local paths, logs, and database content are not exported as span attributes. Set LANGFUSE_DISABLE=1 to force opt-out.

Public Bug Reports ​

Use synthetic data. Never attach real profiles/resumes, databases, secrets, OAuth tokens, generated artifacts, local paths, raw logs, or prompt traces.

From a source checkout, corepack pnpm qa:seed creates a disposable workspace. The release privacy check scans for secret/profile needles, blocked file types, and unsafe distribution paths before publication, but it cannot protect a private file you manually copy into a new tracked path.

Reviewed locale revisions retain the original accepted source snapshot, selected canonical facts, translator/verifier determinations and review history locally. Generation sends that minimized source context to the configured tailoring model under its spend policy. Locale acceptance never submits an application. Accepted TXT/HTML/PDF/DOCX files remain registered local artifacts; failed refreshes preserve prior bytes. See Reviewed Locale Variants.

Private Screening History ​

Screening answers, selected source facts and manual-use text are private local SQLite history. Only deliberate selected facts and exact saved question/posting context go to the configured Apply model lane. General activity and SSE carry safe references. Copying and manual-use attestation grant no form-entry or submission authority.

Optional company briefings fetch only explicitly selected anonymous public pages and send bounded public text plus the reviewed company identity to the enrichment model. They send no profile, mail, resume or search query. The local database retains source snapshots, model receipts and accepted/failure history; shared company history survives removal of its linked jobs.

Selected-job comparison data ​

Reviewing a selected-job cohort is local and makes no model call. Explicit comparison sends only the selected saved posting descriptions, their job identifiers/title/employer context, and usable confirmed achievement excerpts to your configured provider in the Profile lane. Personal contact fields, unconfirmed evidence, declared skill lists, aspirations and milestone activity are not comparison evidence inputs. No external learning-resource research runs.

Cohort revisions and chosen milestones retain private source snapshots, comparison provenance and user completion statements in local SQLite. Historical origins remain after Profile/cohort changes and job deletion. The job-data purge preserves them and reports their retained career_learning_records count. They are not sent in general SSE events or converted into Profile skills, readiness, fit scores, application approvals or submission authority.

Retained Source Proposal History ​

The opt-in source-proposals from-history command checks source hostnames through DNS; it sends no saved posting content to a model and fetches no remote page. Its local source-control receipts retain original posting/Job/run identifiers, input URLs, extraction hashes and bounded saved-content samples. These receipts and rejection/reset decisions survive job deletion and job-data purge, alongside the source registry and locator queue. source-proposals list reads that history without network access or mutations. See Discovery for review and explicit suppression reset.