pi-career 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.4.0 - 2026-10-04
6
+
7
+ ### Added
8
+
9
+ - Implemented application-workspace Gate 1 behind user-only no-argument TUI/RPC `/career-workspace`: explicit strict config-v1-to-v2 migration, one existing owner-only disjoint application root, marker attach/detach, immutable application manifest and append-only status/workflow-original-vacancy/selected-original revisions, and read-only crash/drift reconciliation.
10
+ - Added canonical complete editor previews plus separate confirmation, config/inode compare-and-swap, exact config/root locks, no-clobber hard-link publication, bounded limits, private modes, sync/settlement, idempotency, payload-free failures, and synthetic macOS/Linux filesystem coverage for Gate 1.
11
+ - Added the separately authorized application-workspace transaction for user-authored Markdown/plain-text cover letters: an unchanged exact preview, distinct persistence confirmation, and ordinary workspace-mutation approval precede immutable no-clobber artifact/state publication; view and clear preserve validated history, and no assisted drafting, Core/provider/network call, or submission occurs.
12
+
13
+ ### Changed
14
+
15
+ - Updated the exact lockfile-pinned Pi development suite to 1.0.2, including compatibility coverage for Pi's structured working-directory prompt section and default interactive-mode entry point; the four Pi-provided runtime packages remain wildcard external peers. Pi 1.0.2 removes the vulnerable development shrinkwrap selection of `brace-expansion@5.0.9`, and the strict full audit and publication-readiness check pass with `brace-expansion@5.0.12`.
16
+ - Preserved first-run and v1 compatibility: ordinary setup may safely bootstrap only private `career/`, absent/v1 ordinary mutations continue writing canonical v1, only confirmed workspace-root configuration migrates to v2, and every later writer preserves v2 plus its optional application-root binding while freshly rejecting root overlap.
17
+ - Documented that Gate 1 performs no Core/runtime/provider/model/network/child/session-append action and does not implement assisted workspace artifacts, deletion, broader application files, repair, adoption, archive, or sync. The separate `/career-save` workflow is unchanged.
18
+ - When a persistent application is attached, `/career-vacancy`, `/career-match`, `/career-analyze`, `/career-workbench`, and `career_run context` use workspace files as the only current vacancy/Resume authority: cancelled vacancy saves change neither workspace nor session, match uses the effective Resume, analyze uses only the selected original, and workbench/assistance never auto-submit.
19
+ - Attached `/career-application` shows and updates workspace lifecycle only through a previewed file mutation, and `/career-application clear` detaches without a competing session-only status or vacancy.
20
+ - TUI `/career` is application-first: Applications and Resumes are the only top-level destinations, while Setup, job description, Analyze, Match, Workspace, and Ask Pi are contextual routes/actions. The existing `/career-*` commands remain direct compatibility routes with breadcrumb-aware Back/Escape behavior; Left/Right or Tab switches destinations, and `a` still attaches only after confirmation without activating assistance. Overlay navigation does not call Core or a provider.
21
+ - One Career view model now owns views, items, selection, detail, and attach. TUI overlay and RPC hierarchical select/confirm dialogs are only renderers of that model; those slash commands only choose the starting view, leftover command-specific menus are gone, and opening/browsing never attaches or calls Core.
22
+ - Setup and library views can add a resume root after confirmation (`n` in TUI, Add root in RPC). The action writes config only, reloads the shared model, and does not attach, call Core, or create files.
23
+ - TUI Career overlay now renders a centered, margin-separated, theme-compatible rounded Unicode modal frame with connected separators, consistent interior padding, explicit breadcrumbs/current state/recommended action/safe alternatives, concise contextual hints, and local help. ANSI/Unicode rows and exact previews are measured against the padded inner width, while a terminal-derived row budget preserves the frame and footer and scrolls only content; long catalogs keep selection visible and detail/help support Up/Down scrolling.
24
+ - Overlay/RPC Career UI can create an application, rescan or remove a library root, run analyze/match, edit a vacancy, update status, and open Gate 1 workspace management from the shared view model. Opening and browsing still never attach or call Core; those actions stay confirmation-gated.
25
+ - Overlay empty states, session-created applications, analyze/match result rows, Ask Pi, detach, and vacancy clear stay on the shared view model so `/career` can run as an in-Pi application without leftover command menus.
26
+ - Attached applications can select and immutably bind one eligible original Resume from Library, Analyze, or Match (`o` in TUI) through the existing exact preview and separate confirmation flow. Attached Analyze/Match no longer fall back to an unbound library Resume, and assisted variants remain ineligible.
27
+ - Legacy Applications rows can finish identity-only migration without a matching session or attachment after separately entering exact labels, reviewing exact canonical bytes, and confirming no-clobber publication; list/open, cancellation, drift, and losing concurrent plans remain no-write.
28
+
29
+ ## 0.3.0 - 2026-08-14
30
+
31
+ ### Breaking
32
+
33
+ - Removed Windows support. Package metadata now permits installation only on macOS/Linux, and direct local/Git extension initialization registers no command/tool and fails with stable payload-free `unsupported_platform` guidance before runtime route work, acquisition, compatibility probing, or private stdin.
34
+
35
+ ### Changed
36
+
37
+ - Updated the exact external runtime and managed compatibility boundary to `@revazi/career@0.2.0` / Core 0.2.0 after reviewing the six-target package, registry integrity, SLSA provenance, and unchanged v1 operation/schema semantics. Pi-career validates the exact ordered six-package v2 launcher manifest while delegating native selection and integrity algorithms to the launcher.
38
+ - Decoupled immutable `7ed36c4…` after-study evidence from later source: frozen bytes/trees/deltas remain exact, while current measurements may improve only with unchanged shape/invariants/budgets and no workflow regression relative to that snapshot.
39
+ - Consolidated the model-visible Career Skill while preserving safety invariants and avoiding workflow regressions; the frozen before/after evidence records an aggregate reduction from 25,652 to 21,552 workflow tokens (15.98%).
40
+ - Added a Git-history/source-tree/hash-bound before/optimizing/after token-optimization benchmark phase with Pi Skill discovery/full-load context, actual managed serialization parity, direct tool-call/result/detail/editor surfaces, and independent workflows; semantic/privacy gates prevent savings by dropping required context.
41
+ - Added user-only TUI/RPC `/career-save` for exact preview and separately confirmed no-clobber saving of current Markdown/text materializations on supported macOS/Linux systems, with private managed-directory markers, strict assisted/non-authoritative v2 sidecars, in-memory idempotency, and immediate exclusion-verifying rescan; PDF saves fail closed.
42
+ - Changed assisted-sidecar scanning to quarantine malformed, missing-in-managed-root, duplicate-key, edited, or hash-mismatched artifacts instead of allowing fallback to original analysis/matching eligibility.
43
+ - Expanded the frozen synthetic token benchmark across managed match, suggestion/replacement review, materialization, and evidence/change/document detail hydration outputs, all under explicit common-output budgets.
44
+ - Added mocked release-automation regressions for checked-in hosted-gate invocation, bounded registry propagation, exact npm publish/SLSA attestation formats, fail-closed responses, and publication-to-release ordering.
45
+ - Generalized the trusted-publishing checklist and recorded immutable `v0.2.0` coordinates, incident boundaries, and no-blind-rerun recovery guidance.
46
+ - Expanded synthetic PDF compatibility coverage with pinned Chromium 150 tagged/untagged fixtures, an embedded OFL-licensed Lato subset, a CSS multi-column layout, and fail-closed image-only/malformed/oversized inputs without OCR.
47
+ - Added a reproducible two-page ReportLab 4.4.10 searchable-PDF fixture with pinned generator-wheel provenance, exact extracted text, compressed content, and an embedded Lato subset.
48
+ - Added turn-terminating non-PDF variant review and a bounded TUI `/career-review` flow that requires warning/discard acknowledgment, exact per-change inspection, explicit inclusion, and a later handle/ID-only editor handoff; PDF handles fail closed before selection or materialization.
49
+ - Added a final paged cross-change review and separate prepare choice before `/career-review` can place selected canonical IDs in the editor, with a back path that preserves the in-memory selection for revision.
50
+ - Replaced the final selected-change JSON object with compact labeled records that keep exact IDs, sections, line bounds, before/after text, and both evidence sets visible.
51
+ - Added constant-state final-review navigation that can reopen any selected exact record directly before the separate prepare-or-back decision.
52
+
3
53
  ## 0.2.0 - 2026-08-10
4
54
 
5
55
  ### Added
@@ -16,8 +66,8 @@
16
66
  ### Changed
17
67
 
18
68
  - Replaced package-owned native artifacts with a local-first external resolver: bounded absolute `CAREER_CLI_PATH`, PATH `career`, package-local `@revazi/career`, then bounded acquisition of exact `@revazi/career@0.1.1` unless `PI_OFFLINE=1`.
19
- - Expanded the reviewed external runtime matrix to ARM64/x64 macOS, GNU and musl Linux, and MSVC Windows through the exact eight-target `@revazi/career@0.1.1` launcher. Windows acquisition derives npm and its command shell from validated real installation/system paths, executes no PATH-selected shim, and cancels the detached npm process group.
20
- - Exact managed Core 0.1.1 operation-catalog/schema-bundle compatibility now completes before private stdin opens. The reviewed Career package launcher owns native target/libc/provenance/mode or Windows file invariant/size/format/SHA-256 verification; pi-career caches routes only in memory and never retries an already-started operation on another route.
69
+ - Expanded the reviewed external-runtime acquisition boundary through exact `@revazi/career@0.1.1`, deriving npm and its command shell from validated real installation/system paths, executing no PATH-selected shim, and cancelling the detached npm process group.
70
+ - Exact managed Core 0.1.1 operation-catalog/schema-bundle compatibility now completes before private stdin opens. The reviewed Career package launcher owns native target/libc/provenance/mode/size/format/SHA-256 verification; pi-career caches routes only in memory and never retries an already-started operation on another route.
21
71
  - Removed `runtime/` from source/package artifacts and replaced bundled-runtime/package checks with runtime-resolution, exact Career package, offline failure, and native-free tarball coverage.
22
72
  - Workbench prompts now use `career_run` handles and native proposal payloads rather than model-visible schema discovery and manually reconstructed Core envelopes.
23
73
  - Setup and library flows now rescan immediately, display indexed PDFs and actionable scan notices, and explain the searchable PDF/Markdown/text success path instead of silently showing an empty library.
package/NOTICE CHANGED
@@ -11,11 +11,11 @@ LICENSE-APACHE.
11
11
  pi-career packages no native Career Core binary. Runtime distribution,
12
12
  platform provenance, native integrity verification, and native third-party
13
13
  notices belong to the separately installed or acquired exact
14
- @revazi/career@0.1.1 distribution. Historical evidence for the native binaries
14
+ @revazi/career@0.2.0 distribution. Historical evidence for the native binaries
15
15
  bundled by pi-career v0.1.0 remains in docs/native-dependency-inventory.md and
16
16
  docs/releasing.md but is not part of the current runtime boundary.
17
17
 
18
- Searchable PDF text extraction bundles unpdf 1.8.0, Copyright (c) 2023-PRESENT
18
+ Searchable PDF text extraction bundles unpdf 1.8.1, Copyright (c) 2023-PRESENT
19
19
  Johann Schopplich, under the MIT License preserved at
20
20
  docs/unpdf-LICENSE-MIT.txt. Its bundled serverless PDF.js implementation is
21
21
  derived from Mozilla PDF.js and is distributed under the Apache License 2.0,
package/README.md CHANGED
@@ -7,37 +7,49 @@
7
7
 
8
8
  `pi-career` is a [Pi package](https://github.com/earendil-works/pi) for deterministic resume analysis and conservative vacancy matching, with an optional model-assisted workflow for reviewed resume improvements.
9
9
 
10
- The package's command handlers do not call a model/provider. `/career-workbench` instead prepares a visible private prompt in Pi's editor; only the user's later submission invokes the selected Pi model/provider. At runtime, pi-career never uses a Career Core source checkout or Cargo build. Its optional maintainer compatibility test may read an explicitly supplied, reviewed Core fixture checkout.
10
+ The package's command handlers do not call a model/provider. `/career-workbench` prepares a visible private prompt in Pi's editor, while `/career-review` prepares only an ephemeral review handle and explicitly selected canonical IDs; only the user's later submission invokes the selected Pi model/provider. At runtime, pi-career never uses a Career Core source checkout or Cargo build. Its optional maintainer compatibility test may read an explicitly supplied, reviewed Core fixture checkout.
11
11
 
12
12
  It gives you:
13
13
 
14
14
  - local slash commands for setting up a resume library, analyzing originals, and matching them to a vacancy;
15
+ - a user-only `/career-workspace` flow for an explicitly configured private application root, immutable status/vacancy revisions, selected-original digest binding, and read-only reconciliation;
15
16
  - one compact managed agent tool, `career_run`, for guided work after the deterministic baseline;
16
17
  - a visible workbench handoff that never sends private resume text until you review and submit it yourself;
18
+ - bounded TUI inspection and explicit selection of Core-reviewed non-PDF changes without automatic materialization;
17
19
  - a bounded resolver for a compatible external Career Core runtime;
18
20
  - no bundled native binary, telemetry, vacancy URL fetching, automatic document overwrite, or hidden provider call.
19
21
 
20
22
  Career Core remains authoritative for scores, evidence, warnings, uncertainty, matching, and proposal review. `pi-career` owns the Pi workflow and presentation layer; it does not reimplement Career Core algorithms or schemas.
21
23
 
22
- > **Version note:** this README describes `pi-career@0.2.0`. Published `pi-career@0.1.0` is the historical bundled-runtime release. If `0.2.0` is not yet visible on the npm registry, use a reviewed local checkout or pinned Git commit.
24
+ > **Version note:** this documentation describes `pi-career@0.4.0`. The prior native-free release is `pi-career@0.3.0`; `pi-career@0.2.0` is the earlier native-free release, and `pi-career@0.1.0` is the historical bundled-runtime release.
25
+
26
+ ### `/career` application mode
27
+
28
+ `/career` is a modal application inside Pi, not a prompt that enters the agent loop. It locally lists persistent applications in deterministic order, supports text and lifecycle filters, creates and opens applications, displays the three-component package checklist and derived readiness, and exposes explicit attachment and lifecycle actions. A valid attached application opens directly in detail; browsing another application never attaches it. Existing `/career-application` and `/career-workspace` commands remain compatible fallbacks.
29
+
30
+ Opening, browsing, filtering, viewing readiness, and inspecting bounded local details use only local extension state. Explicit deterministic analysis or matching invokes Career Core locally without invoking a model. None of those actions submits a message, appends a session entry merely for navigation, or places Resume, job-description, application, or Core-result content in model context.
31
+
32
+ Model assistance begins only after the user selects an explicit assistance action, reviews the visible editor handoff, and submits it through normal Pi interaction. Persistent application attachment, Career-specific model-context activation, provider submission, and file mutation remain separate decisions. Ordinary sessions expose no Career Skill path or Career tool schema until a valid assistance-activation record is present and its path-free attachment pointer revalidates.
23
33
 
24
34
  ## Requirements
25
35
 
26
36
  - Node.js 22.19 or newer
27
- - Pi with 0.84.0-compatible package APIs
28
- - a reviewed ARM64/x64 target: macOS, GNU/Linux with glibc 2.35+, musl Linux, or MSVC Windows
29
- - either a compatible local `career` executable or network access for first-use acquisition of exact `@revazi/career@0.1.1`
37
+ - Pi with 1.0.0-compatible package APIs
38
+ - macOS or Linux on ARM64/x64; GNU Linux requires glibc 2.35+, and musl Linux is supported
39
+ - either a compatible local `career` executable or network access for first-use acquisition of exact `@revazi/career@0.2.0`
40
+
41
+ Windows is unsupported. npm enforces the package `os` allowlist; for a local or Git registration, extension initialization fails with stable `unsupported_platform` guidance before registering any command or tool, inspecting `CAREER_CLI_PATH`, searching `PATH`, validating package routes, acquiring npm content, or opening private stdin.
30
42
 
31
43
  ## Install
32
44
 
33
- After the registry confirms the release, install the exact version:
45
+ Install the exact reviewed version:
34
46
 
35
47
  ```bash
36
- pi install npm:pi-career@0.2.0
48
+ pi install npm:pi-career@0.4.0
37
49
  pi list
38
50
  ```
39
51
 
40
- For release-candidate testing, a clean checkout includes reproducible `dist/index.js` and `dist/pdf-worker.js` bundles, so local installation does not require a build or npm install:
52
+ For local-checkout testing, a clean checkout includes reproducible `dist/index.js` and `dist/pdf-worker.js` bundles, so local installation does not require a build or npm install:
41
53
 
42
54
  ```bash
43
55
  cd /absolute/path/to/pi-career
@@ -45,13 +57,6 @@ pi install "$(pwd -P)"
45
57
  pi list
46
58
  ```
47
59
 
48
- On Windows PowerShell, register the same clean checkout with:
49
-
50
- ```powershell
51
- pi install (Resolve-Path .).Path
52
- pi list
53
- ```
54
-
55
60
  Local-path installation loads the checkout in place. After a reviewed update, restart Pi or run `/reload`.
56
61
 
57
62
  To pin a reviewed Git commit instead:
@@ -108,15 +113,21 @@ flowchart TD
108
113
  T -->|Tailor to vacancy| X["Analyze and match the original<br/>Career Core reviews variant changes once"]
109
114
  X --> Y{"Original format"}
110
115
  Y -->|PDF| AA["Return targeted manual changes only"]
111
- Y -->|Markdown/text| AB["Later turn: user selects retained change IDs"]
112
- AB --> AC["career_run materialize<br/>assisted text; still not saved"]
116
+ Y -->|Markdown/text| AB["career_run ends the review turn"]
117
+ AB --> AD["/career-review<br/>inspect notices and exact changes<br/>all IDs start excluded"]
118
+ AD --> AE{"Review and submit selected IDs?"}
119
+ AE -->|No| Z
120
+ AE -->|Yes| AC["Later turn: career_run materialize<br/>assisted text remains in memory"]
121
+ AC --> AF{"Save this local variant?"}
122
+ AF -->|No| Z
123
+ AF -->|Yes| AG["/career-save<br/>review exact files and destination<br/>then confirm separately"]
113
124
 
114
125
  N --> Z["Original remains unchanged<br/>assisted output is non-authoritative<br/>and is never reranked as an original"]
115
126
  Q --> Z
116
127
  U --> Z
117
128
  W --> Z
118
129
  AA --> Z
119
- AC --> Z
130
+ AG --> Z
120
131
  ```
121
132
 
122
133
  ### 1. Start with a transient Pi session
@@ -147,7 +158,7 @@ In Pi, run:
147
158
  /career-setup
148
159
  ```
149
160
 
150
- Choose **Add root** and enter the resume directory. Setup stores the canonical root in private local Pi configuration; it does not copy, move, or edit your resumes.
161
+ Choose **Add root** and enter the resume directory. Setup stores the canonical root in private local Pi configuration; it does not copy, move, or edit your resumes. On first ordinary setup, pi-career may create only the missing agent-directory-relative `career/` config directory as canonical effective-user-owned `0700` beneath the existing canonical Pi agent directory. It never adopts or chmods a pre-existing unsafe object. Workspace configuration remains stricter and requires that private config directory to exist before `/career-workspace` begins.
151
162
 
152
163
  Setup also displays a preferred `variants/` destination. This is suggestion-only: it creates no directory or file and does not authorize a save.
153
164
 
@@ -188,6 +199,8 @@ Then set the vacancy:
188
199
 
189
200
  Paste the vacancy text directly. `pi-career` never fetches a vacancy URL. Career Core validates the text before it becomes the current vacancy.
190
201
 
202
+ If you want the separate Gate 1 local application record, prepare an existing private `0700` directory outside every resume/variation root, then run `/career-workspace`. Configure the root and initialize the current application only after reviewing and confirming each exact mutation. This is optional and does not save an assisted resume.
203
+
191
204
  ### 6. Match your originals
192
205
 
193
206
  ```text
@@ -208,11 +221,11 @@ Choose an original and a guided mode. The command prepares a private prompt in P
208
221
 
209
222
  After you submit, the selected Pi agent uses `career_run` to rerun complete deterministic baselines and Core-review any proposed suggestions, replacements, or vacancy-specific changes. The original remains immutable.
210
223
 
211
- For a non-PDF tailored variation, the agent must stop after review and ask you to select retained change IDs. Materialization can happen only in a later turn with exactly those IDs. For PDFs, the workbench returns targeted manual changes only because extracted text cannot preserve typography, columns, spacing, or graphics.
224
+ For a non-PDF tailored variation, `career_run variant-review` ends the agent turn. Run `/career-review <review-handle>` to inspect every warning/discard and each exact before/after/evidence record; all retained changes start excluded. Explicitly include the IDs you want, review those selected changes together, and separately confirm the handle/ID-only editor handoff before submitting it as a later turn. The selector never materializes or submits automatically. After successful materialization, you may separately run `/career-save <variant-handle>` to inspect the complete local file plan and confirm it; the model cannot invoke saving. For PDFs, the workbench returns targeted manual changes only because extracted text cannot preserve typography, columns, spacing, or graphics; PDF review handles cannot enter selection, materialization, or saving.
212
225
 
213
226
  ## Slash command reference
214
227
 
215
- The workflow commands below require interactive TUI/RPC mode except `/career-vacancy clear`; `/career-tools` is a lightweight tool-surface switch. Slash-command handlers do not invoke a model/provider. `/career-workbench` prepares an editor prompt whose later user submission does. Core-backed commands may resolve or acquire the external runtime before processing private input.
228
+ The workflow commands below require interactive TUI/RPC mode except `/career-vacancy clear`; `/career-review` is TUI-only, `/career-save` and no-argument `/career-workspace` support TUI/RPC, and `/career-tools` is a lightweight tool-surface switch. Slash-command handlers do not invoke a model/provider. `/career-workbench` and `/career-review` prepare editor prompts whose later user submission does. Core-backed commands may resolve or acquire the external runtime before processing private input.
216
229
 
217
230
  ### `/career-setup [status]`
218
231
 
@@ -259,6 +272,23 @@ After clearing—or before working on another company/role—run `/new`. The sam
259
272
 
260
273
  This command manages session state only. It does not create workspace folders or application files.
261
274
 
275
+ ### `/career-workspace`
276
+
277
+ Open the user-only TUI/RPC application-workspace menu. The command accepts no arguments and is not available as a model tool. Print/JSON modes fail before reading config, session-private data, or workspace files.
278
+
279
+ Gate 1 can:
280
+
281
+ - show read-only status and classify drift, interrupted initialization, or crash-left locks/temporary files without repair;
282
+ - explicitly configure one already-existing canonical owner-only `0700` application root, creating or validating its private package marker;
283
+ - initialize the current active application at a package-derived direct-child path with immutable manifest and exact private display-identity metadata;
284
+ - append an immutable full state revision for current status, exact workflow-original vacancy bytes, vacancy clear, or a freshly scanned selected-original digest binding;
285
+ - write or revise a separately authorized user-authored Markdown/plain-text cover letter when a current vacancy and effective resume exist, view the current validated artifact, or clear its current reference while retaining immutable history;
286
+ - detach the root from config without changing the marker or any application file.
287
+
288
+ Every mutation displays a complete canonical preview in the editor, requires the preview to return byte-identically, and then requires a separate confirmation. Writing a cover letter also requires a distinct persistence confirmation before the ordinary workspace-mutation approval; cancellation writes nothing. Configuration and workspace files use owner-only modes, locks, bounded no-clobber publication, sync, and fail-closed identity/disjointness checks. Application roots must remain physically disjoint in both directions from every resume-library root and variation-root suggestion.
289
+
290
+ Workspace files outlive `/career-application clear`, `/new`, session deletion, transient shutdown, detach, package removal, and status `closed`. Gate 1 does **not** save an assisted resume, delete a workspace/root/application, copy or modify an original, save Core/provider output, create assisted cover-letter content, or create notes, `changes.md`, interview files, PDF/DOCX artifacts, repair, adoption, archive, or sync behavior. The cover-letter transaction accepts only content authored by the user in the local editor; it does not call Career Core, a model/provider, or the network, and it does not submit the letter. `/career-save` remains a separate resume-library variation workflow with independent consent.
291
+
262
292
  ### `/career-vacancy [clear]`
263
293
 
264
294
  Set, inspect, replace, or clear the current vacancy.
@@ -322,7 +352,40 @@ The optional resume filter behaves like `/career-analyze`. Available modes are:
322
352
 
323
353
  The command itself calls neither Career Core nor a provider. It puts the complete selected resume—and the vacancy only for tailoring—into Pi's editor. Nothing is sent until you submit. Submitting may persist that message and send it to the provider selected in Pi.
324
354
 
325
- `pi-career` currently does not save the resulting variation to disk.
355
+ The workbench and model never save automatically. Only a later successful non-PDF materialization can be passed by the user to `/career-save` for separate exact local preview and confirmation.
356
+
357
+ ### `/career-review <review-handle>`
358
+
359
+ Review and explicitly select retained changes from a current non-PDF `career_run variant-review` result. This command is available only in TUI mode and only while the ephemeral review handle remains in the current process/session branch.
360
+
361
+ The bounded selector:
362
+
363
+ - requires inspection/acknowledgment of all Core warnings and discarded-change reasons;
364
+ - shows every canonical change as excluded by default;
365
+ - opens a paged exact view of its before text, proposed after text, line bounds, resume evidence, and vacancy evidence;
366
+ - includes a change only after you toggle it from that exact view;
367
+ - requires at least one included canonical ID before continuing;
368
+ - pages all selected exact changes together in a compact labeled view, lets you reopen any selected record directly, and requires a separate final prepare choice with a back option for revisions.
369
+
370
+ Only that final prepare choice creates a short editor message containing the review handle and selected IDs. It does not invoke Career Core, materialize a result, contact a provider, append selection state to the Pi session, save a result, or write a file. Review and submit that editor message manually to start the later materialization turn. Escape cancels without preparing anything.
371
+
372
+ PDF review changes remain manual-application guidance and are rejected by `/career-review`, `career_run materialize`, and `/career-save`.
373
+
374
+ ### `/career-save <variant-handle>`
375
+
376
+ Save one current successful Markdown/text `career_run materialize` result as a new assisted local variant. This user-only command is not a model tool and is available in TUI/RPC mode on supported POSIX systems.
377
+
378
+ Before writing anything, it:
379
+
380
+ 1. revalidates the ephemeral variant and unchanged original;
381
+ 2. derives an eligible direct-child managed variants directory;
382
+ 3. opens a complete canonical preview containing exact destination paths, artifact/sidecar bytes, hashes, and any directory marker;
383
+ 4. requires the preview to be returned byte-identically;
384
+ 5. asks for a separate final confirmation.
385
+
386
+ It then publishes new `0600` files in a `0700` managed directory without replacing existing paths, writes a strict assisted/non-authoritative sidecar, and rescans before reporting success. Missing, malformed, edited, or hash-mismatched assisted metadata is quarantined and never falls back to original eligibility. Saving invokes no Career Core operation, provider, model, network request, or session entry. PDF handles fail closed; the save workflow is supported on pi-career's macOS/Linux platforms with its POSIX-private filesystem contract.
387
+
388
+ Saved files are not securely erased by session deletion, root removal, package removal, or `PI_OFFLINE=1`. Pi-career never automatically overwrites, updates, moves, or deletes them.
326
389
 
327
390
  ### `/career-tools [managed|raw|status]`
328
391
 
@@ -342,7 +405,9 @@ Normal users do not need to call raw JSON tools. The package's Agent Skill instr
342
405
  2. `analyze` and `match` return compact projections backed by complete in-memory Core results;
343
406
  3. suggestion, replacement, and variant proposals must pass the corresponding Core review command;
344
407
  4. `detail` hydrates only the requested evidence, warning, check, change, document, or raw section;
345
- 5. `materialize` requires a prior variant-review handle and explicit user-selected retained IDs.
408
+ 5. non-PDF `variant-review` ends its turn so `/career-review` can collect an explicit local selection and prepare a later user message;
409
+ 6. `materialize` requires that unchanged review handle and exactly the user-selected retained IDs;
410
+ 7. only the user may separately run `/career-save <variant-handle>` for unchanged preview and confirmation.
346
411
 
347
412
  Handles and complete results remain bounded in process memory and disappear on session/branch replacement, reload, or shutdown. They are not result files and cannot be reconstructed safely from chat text.
348
413
 
@@ -360,14 +425,14 @@ When raw mode is explicitly enabled, discovery-first use remains mandatory: capa
360
425
 
361
426
  1. absolute `CAREER_CLI_PATH`;
362
427
  2. `career` on `PATH`;
363
- 3. package-local exact `@revazi/career@0.1.1`;
364
- 4. bounded acquisition of exact `@revazi/career@0.1.1` from the canonical npm registry.
428
+ 3. package-local exact `@revazi/career@0.2.0`;
429
+ 4. bounded acquisition of exact `@revazi/career@0.2.0` from the canonical npm registry.
365
430
 
366
- Runtime installation is separate from loading the local Pi package. `/career-setup`, `/career-library`, `/career-application`, and `/career-workbench` do not need Core. `/career-vacancy`, `/career-analyze`, `/career-match`, `career_run`, and the raw tools do.
431
+ Runtime installation is separate from loading the local Pi package. `/career-setup`, `/career-library`, `/career-application`, `/career-workspace`, `/career-workbench`, and `/career-review` itself do not resolve or invoke Core; `/career-review` requires a still-live review produced earlier by `career_run`. `/career-vacancy`, `/career-analyze`, `/career-match`, `career_run`, and the raw tools do need Core.
367
432
 
368
- Before private document stdin opens, the selected executable must pass the exact managed Career Core 0.1.1 operation and schema compatibility checks. An invalid explicit `CAREER_CLI_PATH` fails without fallback. On Windows, the PATH route remains direct-argv-only and selects a native `career.exe`; npm command shims are not executed through a caller-selected shell.
433
+ Extension initialization requires macOS or Linux and fails unsupported platforms with one payload-free `unsupported_platform` error before registering any command/tool or doing route work. Before private document stdin opens on a supported platform, the selected executable must pass the exact managed Career Core 0.2.0 operation and schema compatibility checks. An invalid explicit `CAREER_CLI_PATH` fails without fallback.
369
434
 
370
- The exact launcher target matrix is:
435
+ The pi-career runtime target matrix is:
371
436
 
372
437
  | Operating system | Architecture | Runtime target | Requirement |
373
438
  | --- | --- | --- | --- |
@@ -377,10 +442,8 @@ The exact launcher target matrix is:
377
442
  | GNU/Linux | ARM64 | `linux-arm64-gnu` | glibc 2.35+ |
378
443
  | musl Linux | x64 | `linux-x64-musl` | detected musl runtime |
379
444
  | musl Linux | ARM64 | `linux-arm64-musl` | detected musl runtime |
380
- | Windows | x64 | `win32-x64-msvc` | native MSVC Windows |
381
- | Windows | ARM64 | `win32-arm64-msvc` | native MSVC Windows |
382
445
 
383
- The platform-specific optional packages are internal launcher details; install or acquire only exact `@revazi/career@0.1.1`.
446
+ The platform-specific optional packages are internal launcher details; install or acquire only exact `@revazi/career@0.2.0`. Pi-career validates the launcher's exact ordered six-package v2 manifest and lockstep versions before direct execution, while the launcher remains authoritative for native selection and integrity. Windows remains unsupported.
384
447
 
385
448
  To prohibit acquisition:
386
449
 
@@ -388,13 +451,6 @@ To prohibit acquisition:
388
451
  PI_OFFLINE=1 pi --no-session
389
452
  ```
390
453
 
391
- On Windows PowerShell:
392
-
393
- ```powershell
394
- $env:PI_OFFLINE = "1"
395
- pi --no-session
396
- ```
397
-
398
454
  Offline Core-backed use then requires a compatible `CAREER_CLI_PATH`, `career` on `PATH`, or package-local launcher. Acquisition receives no resume or vacancy input, but it may leave ordinary npm cache or `_npx` data; this is not secure erasure.
399
455
 
400
456
  ## Privacy and persistence
@@ -403,26 +459,28 @@ Use `pi --no-session` when you do not want a new Pi session JSONL. In a persiste
403
459
 
404
460
  Possible persistence surfaces are distinct:
405
461
 
406
- - **Package config:** canonical resume-root paths, bounded labels, and an optional variation-directory suggestion; never resume text, vacancy text, or full Core output.
462
+ - **Package config:** canonical resume-root paths, bounded labels, an optional variation-directory suggestion, and an optional application-root UUID/path binding; never resume text, vacancy text, or full Core output.
463
+ - **Application workspace files:** an exact root marker, immutable non-content manifest, immutable bounded company/role display identity, append-only state metadata, exact explicitly approved workflow-original vacancy snapshots, selected-original digests, and separately approved user-authored Markdown/plain-text cover-letter revisions; no selected-original bytes, Core result, provider response, prompt, credential, session ID, or environment value.
407
464
  - **Pi session:** consent, application/vacancy workflow entries, bounded result cards, and potentially tool arguments/results or submitted workbench messages.
408
- - **Model provider:** only content you submit through ordinary Pi model interaction; `/career-workbench` makes the private payload visible before submission.
465
+ - **Model provider:** only content you submit through ordinary Pi model interaction; `/career-workbench` makes the private payload visible before submission, while `/career-review` prepares only an ephemeral handle and selected canonical IDs.
466
+ - **Approved local variant files:** exact assisted Markdown/text bytes plus bounded marker/sidecar metadata only after `/career-save` preview and confirmation; never full Core JSON.
409
467
  - **npm cache:** ordinary package-acquisition data, never private Career Core stdin.
410
468
 
411
- `pi-career` does not create payload/result temporary files, export full Core JSON, overwrite originals, or automatically save assisted resumes. Searchable PDF extraction is local, bounded, and network-disabled.
469
+ `pi-career` does not create payload/result temporary files, export full Core JSON, overwrite originals, or automatically save assisted resumes. Explicit `/career-save` files are local, private-mode, assisted/non-authoritative, and excluded from analysis/matching. Searchable PDF extraction is local, bounded, and network-disabled.
412
470
 
413
- See [`SECURITY.md`](SECURITY.md), [`docs/design.md`](docs/design.md), and [`docs/product-flow.md`](docs/product-flow.md) for the complete boundary and threat model.
471
+ See [`SECURITY.md`](SECURITY.md), [`docs/design.md`](docs/design.md), and [`docs/product-flow.md`](docs/product-flow.md) for the complete boundary and threat model. Synthetic hardening evidence and its limitations are indexed in [`docs/hardening-validation.md`](docs/hardening-validation.md).
414
472
 
415
473
  ## Current limitations
416
474
 
417
475
  - Supported original formats: searchable PDF, Markdown, and UTF-8 text.
418
476
  - No OCR, DOCX/Pages editing, vacancy URL fetching, or PDF layout reconstruction.
419
- - No automatic resume or application-workspace saving.
477
+ - No automatic resume saving. Application workspaces persist only explicitly previewed status/vacancy/original bindings and the separate confirmation-gated user-authored Markdown/plain-text cover-letter revisions; assisted resume artifacts and package deletion remain unimplemented separate gates.
420
478
  - PDF workbench output is targeted manual guidance only.
421
479
  - Assisted variants remain non-authoritative and cannot be reranked as originals.
422
480
  - Matching is conservative workflow guidance, not a hiring prediction or proprietary ATS simulation.
423
- - Reviewed external native targets are `darwin-arm64`, `darwin-x64`, `linux-x64-gnu`, `linux-arm64-gnu`, `linux-x64-musl`, `linux-arm64-musl`, `win32-x64-msvc`, and `win32-arm64-msvc`.
481
+ - Supported runtime targets are `darwin-arm64`, `darwin-x64`, `linux-x64-gnu`, `linux-arm64-gnu`, `linux-x64-musl`, and `linux-arm64-musl`; Windows is unsupported.
424
482
 
425
- The future application-workspace contract is documented in [`docs/application-workspaces.md`](docs/application-workspaces.md); those filesystem-writing phases are not implemented.
483
+ Application-workspace Gate 1, the separately authorized user-authored cover-letter transaction, and the still-unimplemented assisted-resume/deletion protocols are documented in [`docs/application-workspaces.md`](docs/application-workspaces.md) and [`docs/cover-letter-contract.md`](docs/cover-letter-contract.md). Neither implemented workflow authorizes or implies Gates 2–4.
426
484
 
427
485
  ## Development
428
486
 
@@ -433,6 +491,7 @@ npm ci
433
491
  npm run build
434
492
  git diff --exit-code -- dist/index.js dist/pdf-worker.js
435
493
  npm run bench:tokens
494
+ npm run bench:tokens:compare
436
495
  npm run check
437
496
  npm run test:runtime-resolution
438
497
  npm run test:career-package
@@ -445,6 +504,8 @@ npm run test:compat
445
504
  git diff --check
446
505
  ```
447
506
 
507
+ `npm run bench:tokens` collects the current synthetic model-visible surfaces, including Pi's stable always-visible Skill name/description metadata and the complete on-demand `career-core` Skill for matching career tasks. Linked Skill references and machine-specific discovery paths stay outside that boundary. `npm run bench:tokens:compare` verifies the surface digest, immutable `c7d7634…` before and `7ed36c4…` after source/Skill trees and frozen bytes from Git history, exact frozen before/after deltas, managed serialization parity, semantic/privacy invariants, budgets, and no current workflow regression relative to the frozen after evidence. Later source may differ and improve without rewriting that historical snapshot. The finalized frozen evidence records 25,652 → 21,552 aggregate workflow tokens (15.98% reduction) with no workflow regression.
508
+
448
509
  `npm run test:career-package` is the network-capable exact-package integration test. `npm run test:compat` skips unless an explicitly reviewed fixture checkout is provided:
449
510
 
450
511
  ```bash
@@ -456,7 +517,17 @@ CAREER_CORE_FIXTURE_ROOT=/absolute/path/to/reviewed/career-core \
456
517
 
457
518
  ## Security and release provenance
458
519
 
459
- The exact reviewed external runtime coordinate is [`@revazi/career@0.1.1`](https://www.npmjs.com/package/@revazi/career/v/0.1.1), published from Career Core commit [`0318b3b0993ee23093c8f023757fa7e4d8b3b8e0`](https://github.com/revazi/career-core/tree/0318b3b0993ee23093c8f023757fa7e4d8b3b8e0). Its launcher owns native target/libc selection and package metadata, provenance, mode or Windows file invariant, size, format, and SHA-256 verification.
520
+ The exact reviewed external runtime coordinate is [`@revazi/career@0.2.0`](https://www.npmjs.com/package/@revazi/career/v/0.2.0), published from Career Core commit [`536690632884c17336cc3c108f1bba0f254b862b`](https://github.com/revazi/career-core/tree/536690632884c17336cc3c108f1bba0f254b862b). Its launcher owns native target/libc selection and package metadata, provenance, file invariants, size, format, and SHA-256 verification. Registry integrity and SLSA v1 provenance were reviewed for the user-facing launcher and all six lockstep native packages. Pi-career validates that exact six-package v2 manifest and supports only its macOS/Linux targets.
521
+
522
+ Published `pi-career` v0.3.0 coordinates are retained for verification:
523
+
524
+ - npm: [`pi-career@0.3.0`](https://www.npmjs.com/package/pi-career/v/0.3.0)
525
+ - Git commit: [`2c0da9ff623b50cc02a7b5bccd3cb047596d947e`](https://github.com/revazi/pi-career/tree/2c0da9ff623b50cc02a7b5bccd3cb047596d947e)
526
+ - npm integrity: `sha512-u/odRK/KMYXhIt/lvGm93RFmQIwBQZV0qbAf1vs/GsNH8Fx/X2f+p+F1iyUYtMi5RH9++SkdhEN8CR2XBScyBw==`
527
+ - npm shasum: `3ad37db78cb76330838fbb3efe722c1cff4d8d00`
528
+ - same-SHA six-target compatibility: [run `31791011739`](https://github.com/revazi/pi-career/actions/runs/31791011739)
529
+ - OIDC publication and registry verification: [run `31791158472`](https://github.com/revazi/pi-career/actions/runs/31791158472)
530
+ - GitHub Release: [`v0.3.0`](https://github.com/revazi/pi-career/releases/tag/v0.3.0), with no custom assets
460
531
 
461
532
  Historical published `pi-career` v0.1.0 coordinates are retained for verification:
462
533
 
@@ -465,7 +536,7 @@ Historical published `pi-career` v0.1.0 coordinates are retained for verificatio
465
536
  - npm integrity: `sha512-mmbDdWDyWz77f2uLzZECJT9E6w1ZRCJjYFrUnZd3ldoS6ehEa5DrCENIfavHR5xMOFi0of6AVQ35ZTxwpeDeAQ==`
466
537
  - GitHub Release: [`v0.1.0`](https://github.com/revazi/pi-career/releases/tag/v0.1.0)
467
538
 
468
- That historical release bundled native artifacts; `pi-career@0.2.0` does not. Historical evidence remains in [`docs/native-dependency-inventory.md`](docs/native-dependency-inventory.md), [`docs/releasing.md`](docs/releasing.md), and [`docs/licenses/`](docs/licenses/).
539
+ That historical release bundled native artifacts; `pi-career@0.2.0` and later do not. Historical evidence remains in [`docs/native-dependency-inventory.md`](docs/native-dependency-inventory.md), [`docs/releasing.md`](docs/releasing.md), and [`docs/licenses/`](docs/licenses/).
469
540
 
470
541
  Use [Issues](https://github.com/revazi/pi-career/issues) only for sanitized bugs and scoped feature requests. Follow [`SECURITY.md`](SECURITY.md) for private vulnerability reports. Never attach real resumes, vacancies, credentials, provider responses, or Pi session files to a public issue.
471
542
 
package/SECURITY.md CHANGED
@@ -6,21 +6,21 @@ Do not open an ordinary issue with vulnerability details. Use a private Security
6
6
 
7
7
  ## External runtime boundary
8
8
 
9
- pi-career packages no native Career Core binary and has no runtime npm dependency or lifecycle script. Resolution order is fixed:
9
+ pi-career packages no native Career Core binary and has no runtime npm dependency or lifecycle script. It supports only macOS and Linux. On an unsupported platform, extension initialization registers no command or tool and fails with one stable payload-free `unsupported_platform` error before explicit/PATH resolution, package validation, acquisition, compatibility probing, or private stdin. On supported platforms, resolution order is fixed:
10
10
 
11
11
  1. bounded absolute `CAREER_CLI_PATH`;
12
12
  2. `career` on PATH;
13
- 3. package-local exact `@revazi/career@0.1.1`;
14
- 4. bounded acquisition of exact `@revazi/career@0.1.1` from the canonical npm registry;
13
+ 3. package-local exact `@revazi/career@0.2.0`;
14
+ 4. bounded acquisition of exact `@revazi/career@0.2.0` from the canonical npm registry;
15
15
  5. stable payload-free installation guidance.
16
16
 
17
17
  There is no sibling-checkout, Cargo, source-build, arbitrary executable download, or unpinned package fallback. `PI_OFFLINE=1` disables acquisition. A successful route is cached only in memory and invalidated when `CAREER_CLI_PATH` or `PATH` changes. An invalid explicit override fails without fallback.
18
18
 
19
- Every caller-controlled route must pass the exact managed Core 0.1.1 operation catalog and required self-contained schema bundles before private stdin opens. Compatibility probes contain no private document input. An automatically selected executable that later fails before its operation emits `spawn` may advance once; cancellation, timeout, and any already-started operation never retry another route.
19
+ Every caller-controlled route must pass the exact managed Core 0.2.0 operation catalog and required self-contained schema bundles before private stdin opens. Compatibility probes contain no private document input. An automatically selected executable that later fails before its operation emits `spawn` may advance once; cancellation, timeout, and any already-started operation never retry another route.
20
20
 
21
- The package-local/acquired `@revazi/career` launcher is invoked directly with the real Node executable. Pi-career requires the exact v2 launcher manifest and ordered eight-package catalog. The launcher owns native target/libc, lockstep package identity, provenance, regular-file type, Unix mode or Windows file invariant, size, format, architecture, and SHA-256 checks. The reviewed targets are ARM64/x64 macOS, GNU and musl Linux, and MSVC Windows; pi-career does not duplicate the launcher's native verification algorithms.
21
+ The package-local/acquired `@revazi/career` launcher is invoked directly with the real Node executable. Pi-career validates its exact v2 manifest, including the ordered six-package lockstep optional-dependency map, declared file allowlist, and `career` bin. The launcher owns native target/libc, package provenance, regular-file type and mode, size, format, architecture, and SHA-256 checks for pi-career's six supported macOS/Linux targets; pi-career does not duplicate those native verification algorithms.
22
22
 
23
- Acquisition invokes the npm CLI derived from real `process.execPath`, rejects ambiguous/conflicting `npm_execpath`, sanitizes npm tree/registry/script-shell overrides, pins the canonical registry/package/version, includes optional native packages, and disables scripts. It never invokes PATH-selected npm/npx. Windows acquisition additionally derives npm from the real Windows Node layout, validates `SystemRoot`/`System32/cmd.exe`, rejects conflicting `ComSpec`, and never executes a PATH `.cmd` shim as the Career route. Acquisition receives no private stdin, has fixed timeout/stdout/stderr bounds, and uses detached process-group termination—including Windows `CTRL_BREAK`—for descendants. npm cache and `_npx` data may remain afterward; this is not secure erasure.
23
+ Acquisition invokes the npm CLI derived from the real Unix `process.execPath` installation, rejects ambiguous/conflicting `npm_execpath`, sanitizes npm tree/registry/script-shell overrides, pins `/bin/sh` and the canonical registry/package/version, includes optional native packages, and disables scripts. It never invokes PATH-selected npm/npx. Acquisition receives no private stdin, has fixed timeout/stdout/stderr bounds, and uses detached Unix process-group termination for descendants. npm cache and `_npx` data may remain afterward; this is not secure erasure.
24
24
 
25
25
  ## Process and data boundary
26
26
 
@@ -30,7 +30,7 @@ The process adapter creates no career payload/result temporary file and performs
30
30
 
31
31
  `/career-vacancy`, `/career-match`, and `/career-analyze` use the same helper; setup/library scanning and application state remain local. `/career-workbench` does not call a provider, model, or Core process; it only prepares a bounded ordinary Pi editor message containing selected private source. Nothing is sent automatically. If submitted, Pi may persist it and send it to the selected provider.
32
32
 
33
- Global config stores only canonical root paths, bounded labels, and an optional variation-directory suggestion in an agent-directory-relative `0700` directory with atomic `0600` writes. Scans are bounded, UTF-8 strict, and symlink-free. Searchable PDFs are limited to 10 MiB and 20 pages and parsed in a package-owned worker with fixed time, memory, and result ceilings. Network fetch, eval, WASM, streaming, auto-fetch, and system-font lookup are disabled; OCR is not performed. Source text and full Core results are never written to global config or logs.
33
+ Global config stores only canonical resume-root paths, bounded labels, an optional variation-directory suggestion, and an optional application-root UUID/path binding. First ordinary setup may create only the missing agent-directory-relative `career/` directory as canonical effective-user-owned `0700` beneath an existing canonical Pi agent directory; pre-existing unsafe objects are never adopted or chmodded, and workspace configuration requires that private directory already exist. Owner-only `0600` config locks plus byte/inode compare-and-swap protect writes. Ordinary absent/v1 mutations remain canonical v1 while no workspace is attached; only confirmed **Configure application root** migrates to strict v2, after which every writer preserves v2 and freshly rejects physical overlap. Scans are bounded, UTF-8 strict, and symlink-free. Searchable PDFs are limited to 10 MiB and 20 pages and parsed in a package-owned worker with fixed time, memory, and result ceilings. Network fetch, eval, WASM, streaming, auto-fetch, and system-font lookup are disabled; OCR is not performed. Source text and full Core results are never written to global config or logs. User-only no-argument `/career-workspace` Gate 1 may separately persist a non-content root marker/manifest, append-only full status metadata, exact explicitly approved workflow-original vacancy bytes, and selected-original digests under one existing owner-only `0700` root disjoint from every resume/variation root. Every mutation requires unchanged complete preview plus separate confirmation and uses bounded private no-clobber publication; workspace actions invoke no Core/runtime/provider/model/network/child process and append no session entry. Assisted workspace artifacts, deletion, repair/adoption/archive/sync, and broader files are not implemented.
34
34
 
35
35
  Only a strictly shaped, bounded, allowlisted `career.error.v1` may cross a known nonzero Core failure. Other failures expose stable payload-free `career.pi_error.v1`. Runtime code must not log or expose source/result text, raw errors, stderr, executable paths, hashes, platform details, environment values, npm diagnostics, or credentials.
36
36
 
@@ -46,7 +46,7 @@ This is not secure erasure and does not remove shell history, npm cache, backups
46
46
 
47
47
  ## Installation and supply chain
48
48
 
49
- Pi packages execute with the user's permissions. Install only a reviewed clean local checkout, public Git source pinned to a reviewed full commit, or public npm package pinned to an exact reviewed version. Review the tracked TypeScript bundle, external resolver, package allowlist, registry metadata, and native package CI/provenance. Normal pi-career installation has no npm lifecycle script, post-install runtime download, Cargo/Rust build, packaged native artifact, or production/optional runtime dependency. The generated PDF worker contains lockfile-pinned `unpdf` 1.8.0 and its included license notice.
49
+ Pi packages execute with the user's permissions. Install only a reviewed clean local checkout, public Git source pinned to a reviewed full commit, or public npm package pinned to an exact reviewed version. Review the tracked TypeScript bundle, external resolver, package allowlist, registry metadata, and native package CI/provenance. Normal pi-career installation declares `os: ["darwin", "linux"]` and has no npm lifecycle script, post-install runtime download, Cargo/Rust build, packaged native artifact, or production/optional runtime dependency. The generated PDF worker contains lockfile-pinned `unpdf` 1.8.0 and its included license notice.
50
50
 
51
51
  `npm run audit:production` and `npm run audit:full` must both report zero vulnerabilities at explicit `--audit-level=low`. Audit and pack checks derive npm from real Node, verify inherited `npm_execpath`, remove tree/severity overrides, and reject duplicate decoded JSON keys. Package extraction uses verified root-owned `/usr/bin/tar`. The package check proves the tarball has no `runtime/`, native binary, `node_modules`, or Pi package contents and declares exactly four wildcard external peers. `check:publish` performs no publication.
52
52