The product problem.

Career information tends to fragment across old CVs, job boards, notes and application portals. Generic AI tools add another problem: a polished answer can lose the connection to the fact that supports it.

The first-use flow now starts where many people already are: an existing CV. CareerOS creates the smallest valid, revisioned profile first, imports the document locally within fixed limits and leaves every extracted candidate unconfirmed. The user lands on fact review instead of a half-created account or an unexplained error.

What the system must protect.

The architecture follows four product constraints:

  1. Private career records, generated documents and analysis stay on the device.
  2. LLM-backed matching and coaching require an approved local runtime; there is no cloud-model fallback.
  3. Generated suggestions cannot silently replace source facts or their revision history.
  4. Backups, exports and erasure must cover both structured records and local artifacts coherently.

The design decision.

The hard part was not adding a chat panel. It was building a boundary between evidence, deterministic workflow state and model interpretation. Those three things have different failure modes and should not share one vague data structure.

I separated them into a career vault, reproducible readiness and application records, and schema-validated local analysis pipelines. The interface can show where a conclusion came from and which corrective action belongs in the source record.

A supervised local runtime.

Tauri owns the desktop shell and supervises a loopback FastAPI sidecar. React provides the workspace, SQLite and local artifacts hold the durable record, and a managed llama.cpp-compatible runtime performs required LLM analysis without becoming a storage layer.

A supervised local runtime. Evidence and workflow state remain durable; local inference receives explicit task context.SYSTEM VIEW / CAREEROSTAURI + REACTFASTAPISQLITE VAULTLOCAL LLMDOCUMENTS+ JOBSVERSIONED DELIVERY PATH
Evidence and workflow state remain durable; local inference receives explicit task context.

Why this stack fits a private desktop utility.

Each boundary keeps a different responsibility local and makes its operational cost visible.

T01 The choice

Tauri 2 owns the desktop shell and native lifecycle.

Why
CareerOS needs an installable workspace that can supervise the bundled sidecar, constrain native permissions and coordinate local files and backups. Tauri provides that boundary while React remains responsible for the interface.
What I ruled out
Electron would package another browser runtime around the same local services, while a browser-only build could not honestly own the Python process, local model runtime and native artifact lifecycle.
What it cost
I accept Rust integration, operating-system prerequisites and cross-platform packaging work instead of pretending the interface is a standalone website.
T02 The choice

A loopback FastAPI sidecar owns the application services.

Why
The career domain benefits from Pydantic validation, SQLAlchemy transactions, Alembic migrations and Python document and analysis tooling. A narrow local API gives the React workspace one explicit contract to those capabilities.
What I ruled out
Moving everything into Rust would require rebuilding that service layer and its Python-oriented integrations; putting it in the browser would expose storage and local-runtime concerns to an environment that cannot supervise them.
What it cost
That leaves me responsible for starting, authenticating and stopping two processes together, then packaging the sidecar without weakening its loopback boundary.
T03 The choice

SQLite and local artifacts form the durable vault.

Why
The product is a locally owned personal workspace rather than a shared hosted service. SQLite provides transactions, explicit migrations and a portable database that can participate in the same backup and erasure workflow as generated documents.
What I ruled out
A separate database server would add an administered process and credentials; a cloud store would add a network and provider data boundary. Neither solves a shared-service requirement in this product’s scope.
What it cost
The tradeoff is local-utility concurrency and scale. Migrations, archive preflight and verified restore therefore need deliberate engineering.
T04 The choice

A managed llama.cpp-compatible runtime performs required analysis locally.

Why
Matching and coaching operate on private career evidence. Keeping inference on the device preserves the stated boundary, and schema-validated tasks stop the model from becoming a second source of record.
What I ruled out
A cloud API would simplify first use and offer different model capacity, but it would send task context outside the device and make privacy depend on a provider and network connection.
What it cost
Users take on model provisioning, hardware-dependent latency and a narrower set of runtimes. The application must fail closed when the approved local model is unavailable.

Decisions that make it a utility.

The useful work happens before and after the model call.

D01

Create the record before importing the CV

The first-use flow creates a minimum revisioned profile, then runs a bounded local import. Extracted facts remain candidates until the user reviews them, so a CV can accelerate setup without becoming unquestioned truth.

The trade-offOnboarding needs an explicit review step, but failed or partial extraction cannot leave the vault in an ambiguous state.

D02

Journal private mutations before changing owned data

Reset, restore, erasure, packaged migrations and source, photo or resume publication persist bounded purpose-specific intent before they mutate private state. Recovery reopens stable regular-file descriptors and verifies identity, size and digest before it converges or retries.

The trade-offEvery maintenance path carries lifecycle and recovery logic, but a restart or ambiguous commit cannot silently strand a half-applied vault operation.

D03

Give agents a separate read-only door

Agent Access asks the signed-in user to choose scopes and reauthenticate before displaying a bearer token once. Grants expire and can be revoked; the installable CLI and MCP server expose a closed set of read-only tools over stdio, not a general prompt or remote write API.

The trade-offUsers still need to configure their agent client, and an external client may transmit the data it reads. The narrower contract keeps automation useful without sharing the desktop session.

How the product is verified.

Release checks for v1.11.1 passed 2,194 backend tests; 7 were skipped as expected. Total coverage reached 81.91%, with branches included. Another 476 frontend tests passed across 79 files, and the release tree passed all 27 Rust tests. Migration, archive, journal, recovery and concurrent-publication suites exercise the failure paths behind the new lifecycle controls.

Protected-branch CI, CodeQL and hardened-container checks are green on commit 96ca0f8. A non-publishing rehearsal and the signed-tag workflow independently assembled and exercised six native packages. The same Agent Access wheel bytes were smoke-tested on Linux, macOS and Windows with Python 3.12 and Python 3.13 before the immutable release published 26 digest-bound assets.

What exists today.

The v1.11.1 release is a working desktop utility with CV-first setup, a Career Vault, guided search, a revisioned Job Library, one application timeline per opportunity, a resume studio, archive v6 and required local analysis. Reset, restore, complete erasure, migrations and private-file publication now have restart-durable recovery paths.

Rotating session families, fail-closed configuration and strict provider and local-runtime response envelopes protect the loopback boundary. Public diagnostics are content-free, while forced-colors, keyboard and WCAG checks cover login and Agent Access in English and Italian across the supported responsive layouts.

The authenticated desktop now manages grants for seven read-only operations exposed through a bearer-token-authenticated CLI and stdio MCP server. Both commands ship in the release wheel. Codex, Claude Code and shell scripts can inspect a deliberately small view of one authorized account, but they cannot edit the vault, invoke free-form prompts or open a remote transport.

It does not claim that an LLM can decide a career. The model helps interpret an owned body of evidence; the user keeps the record, the source and the final decision.

Evidence ledger.

The current repository records these reproducible checks and boundaries:

Backend
The v1.11.1 release suite passed 2,194 backend tests; 7 were skipped as expected. Total coverage reached 81.91%, with branches included.
Frontend + shell
All 476 frontend tests in 79 files and all 27 Rust tests pass. License, icon, bundle, browser, container and supply-chain contracts run on the same release commit.
Restart-durable recovery
Persisted lifecycle states and bounded, checksummed journals let reset, restore, erasure, packaged migrations and private-file publication converge after a restart without trusting an unbounded path or payload.
Sessions and diagnostics
Single-use refresh rotation belongs to persisted session families, replay revokes the family and maintenance sessions cannot enter the workspace. Search and runtime diagnostics cross public boundaries only through a closed, content-free typed registry.
Agent Access
The desktop issues scoped, revocable grants for seven read-only operations exposed through the CLI and MCP server. The release ships both commands in an installable Python wheel, shows each bearer token once and stores only its digest.

Verified release v1.11.1 Verified on

What this case can prove

This case study describes the immutable v1.11.1 release at commit 96ca0f8. Its verified signed tag and 26 published assets follow a non-publishing rehearsal across six native targets and six Agent Access OS/Python combinations. Checksums and GitHub provenance bind bytes to the release, but native installers remain unsigned community builds without platform signing or notarization. It does not claim employment outcomes, model accuracy on private user data or support for every local model and machine.

Visit the working project