Skip to content

Profile & Settings API

This route family owns candidate facts, preferences, discovery configuration, ordinary settings, and credential references. The important distinction is authority: profile facts and preferences live in the profile model; runtime settings control product behavior; secrets use the credential boundary.

For every request/response field, use the complete contract.

Candidate Profile

RoutePurpose
GET /v1/profileRead the normalized candidate profile and current preferences.
PATCH /v1/profileSave validated profile fields and preference changes.
GET /v1/profile/preview.htmlRender the baseline profile resume as HTML.
GET /v1/profile/preview.pdfRender the baseline profile resume as PDF.

Profile writes are explicit saves/autosaves of canonical candidate data. A job tailoring run consumes a versioned snapshot; it does not silently mutate the profile to fit a posting.

Each resume.experience_entries[] record may include summary. The field defaults to an empty string, remains optional for existing and new roles, and renders as non-bulleted position context between the role heading and its achievement bullets only when non-empty.

Achievement numbers are authored with the experience bullet or its structured achievement evidence. resume_constraints.real_metrics remains in the profile wire shape only as a non-authoritative compatibility projection. Derived achievement values lead the list; unmatched values already present in normalized storage are carried forward as unassigned legacy data so GET/PATCH round-trips cannot silently delete user facts. PATCH does not accept new free-floating metrics, and it drops derived values whose achievement was removed or changed. Neither compatibility category authorizes a generated claim; claim authority comes from the mapped achievement itself.

Discovery Controls

SurfaceRepresentative routes
Runtime discovery preferencesGET/PATCH /v1/discovery/settings
Source registryGET/POST /v1/discovery/sources, source state and preview routes
Review queueslocator candidates, quarantine, and manual-capture routes
Feedbackdiscovery feedback and role-match decision routes

These controls decide where discovery may look and how proposed sources or jobs enter the system. They do not hold provider credentials or raw feed contents.

Settings And Credentials

RouteStorage boundary
GET/PATCH /v1/settingsFile-backed non-secret Settings values in config.json; no Discovery-page values.
GET/PATCH /v1/discovery/settingsSQLite-backed discovery controls, including scheduling.
GET /v1/credentialsAvailability/status metadata, not secret values.
PATCH /v1/credentialsStore or replace a credential through the local credential adapter.
PATCH /v1/credentials/batchAtomically replace or remove one guided provider configuration.
DELETE /v1/credentials/:keyRemove a stored credential.
GET /v1/providers/statusRead-only sanitized Codex/Claude/Google configuration and readiness; never copies ambient Codex auth.
GET /v1/providers/modelsRead-only sanitized model choices in stable Codex/Claude/Google order from each authenticated provider runtime; never copies ambient Codex auth.
POST /v1/providers/codex/verifyExplicitly validate and import a reusable normal Codex CLI auth.json once when isolated auth is absent, then verify isolated auth without a model call.
GET /v1/extension/pairing-tokenRead the local extension pairing state.
POST /v1/extension/pairing-token/rotateRotate the token immediately and disconnect existing extension clients.
GET /v1/browser-capabilitiesRead managed/optional capability states plus transient supported-browser candidates and their selectable profiles as opaque IDs and safe labels; no local path is returned or adopted.
POST /v1/browser-capabilities/:capabilityId/enableExplicitly adopt exactly one transient detectedBrowserId or one write-only executablePath for an optional capability.
POST /v1/browser-capabilities/:capabilityId/disableDisable an optional capability immediately.
POST /v1/browser-capabilities/authenticated-linkedin-browser/profile-copyCopy exactly one explicitly selected detected profile by opaque browser/profile IDs, retain the legacy browser-only Default arm, or accept one write-only manual source path; every arm requires explicit consent.

Credential responses expose enough state for the UI to show whether a provider is configured, but do not return stored secret material. Guided provider replacement rolls back on failure; an unrecoverable rollback is reported as an explicit sanitized store failure. See the Security guide for the user-facing trust boundary.

The Codex verify response remains secret-free: it reports only provider, boolean result, bounded status, and a bounded message. The explicit import never overwrites JobCtrl's existing isolated auth or changes the normal Codex home. It invokes the same copy-once behavior retained by setup and generation.

Browser detection is read-only discovery, not consent. The list response may offer supported Chrome/Chromium candidates as bounded { id, label, profiles } values. Each profile contains only an opaque transient ID and Chrome's bounded display label; executable, user-data, and profile paths stay inside the worker, and nothing is launched, copied, or persisted. Enablement is a strict XOR input: send either { detectedBrowserId } or { executablePath }, never both or neither. A detected ID is resolved again at mutation time. If it is stale or no longer available, enablement fails closed with 400 browser_capability_failed and does not retain or fall back to an earlier path.

PATCH /v1/settings stores provider-scoped model choices as preferred_models in config.json and returns them as preferredModels. Each supplied non-null ID must be in the current catalog for a ready provider; null clears a choice even when that provider is unavailable. The setting contains provider and model IDs only, never credentials or account metadata. The settings and discovery responses also include effective-source and activation metadata for managed controls.

config.json field reference

~/.jobctrl/config.json is one JSON object containing non-secret values owned by the Settings routes. The API returns camel-case field names, while API writes persist the canonical snake-case keys below.

This file owns General settings, provider connection metadata, model-execution policy, compensation-source policy, and browser-adoption metadata. Every durable control composed on /discovery is stored in SQLite instead.

File fieldValue and defaultMeaning
apply_concurrencyInteger 1–16, default 1Maximum number of Apply jobs processed concurrently by the standing loop.
pipeline_internal_concurrencyInteger 1–16, default 1Shared internal parallelism for newly started manual Pipeline actions and automatic profile-update preparation batches.
worker_activity_slotsInteger 1–64, default 4Desired Python Temporal activity capacity. A saved change becomes active after the worker restarts.
daily_budget_usdNon-negative number, default 25Daily LLM spend ceiling in USD. 0 disables the daily ceiling.
analysis_legsNon-empty array of codex, claude, and/or google; default all threeProvider legs used by newly started employer-analysis work.
tailoring_generator_modelsNon-empty array of model IDs or null; default nullOrdered generator-model policy for newly started tailoring workflows. null uses the provider/default policy.
tailoring_judge_modelModel ID or null; default nullJudge model for newly started tailoring workflows. null uses the provider/default policy.
tailoring_judge_min_scoreNumber 0–1, default 0.82Minimum judge score for accepting a tailored candidate.
apply_max_budget_usdNon-negative number, default 5Per-application AI-agent budget cap in USD.
apply_timeout_secondsInteger 60–3600, default 900Time limit for one application agent run.
score_criteriaString up to 8,000 characters, default ""User scoring guidance consumed by subsequent scoring runs.
target_criteriaString up to 8,000 characters, default ""Additional target-company or role guidance consumed by subsequent scoring runs. This is guidance, not the target-search title list.
preferred_modelsObject keyed by codex, claude, and/or google; default {}Preferred model ID for each provider. It contains model identifiers only, never credentials.
compensation_sourcesOptional object; absent by defaultSaved user-owned Levels.fyi and Glassdoor source-policy choices. It is written through /v1/compensation/sources, not /v1/settings.
provider_connectionsOptional object; absent by defaultNon-secret Claude/Google route, project, region, profile, and credential-path configuration written through the Credentials API. Actual API keys remain in Keychain.
browser_capabilitiesOptional object; absent by defaultNon-secret adoption metadata for optional system-browser capabilities. Copied browser contents remain outside this file.

Within compensation_sources, the supported source keys are levels_fyi and glassdoor. Each source stores enabled and access_mode; levels_fyi also stores europe_coverage_confirmed. These are policy declarations only: the file does not contain credentials, feed locations, or compensation records.

Which Screen Owns What?

ScreenOwns
Profile (/profile)Candidate facts, experience, skills, evidence, resume content.
Preferences (/preferences)Target role, location, work model, and fit/tailoring preferences.
Discovery (/discovery)Target search, sources, scheduling, quarantine, and capture controls.
Settings → General (/settings)Spend/apply/worker controls and compensation source policy (not a feed connection).
Settings → Credentials (/settings/credentials)Provider modes, credential presence, and explicit Codex verification.
Settings → Model selection (/settings/models)Provider-scoped preferred model IDs plus analysis and tailoring execution policy.
Settings → Browser & extension (/settings/browser)Browser capability adoption/removal, consented profile copy, and extension pairing/rotation.

This split keeps a configuration change from masquerading as candidate evidence.