diff --git a/.claude/commands/apply.md b/.claude/commands/apply.md index 69fdeec..33db98e 100644 --- a/.claude/commands/apply.md +++ b/.claude/commands/apply.md @@ -280,3 +280,5 @@ List the files written: - `cover_letters/cover__.tex` Tell the user: "Both files are ready for your review. Open them to check the final output before compiling." + +Also mention: once they have actually submitted the application, `/outcome ` logs it in the tracker and starts the per-application record that `/setup` later uses to calibrate the fit framework. diff --git a/.claude/commands/outcome.md b/.claude/commands/outcome.md new file mode 100644 index 0000000..069ee9c --- /dev/null +++ b/.claude/commands/outcome.md @@ -0,0 +1,124 @@ +# /outcome - Record the Result of an Application + +You are recording what happened to a job application: progress updates (interview invitations, stages completed, offers) and final resolutions (hired, rejected, no response). The data lands in two places the framework already reads but nothing systematically writes: + +- `job_search_tracker.csv` - the status column that `/scrape` and `/rank` use for dedup and exclusion +- `documents/applications/_/` - the per-application archive (posting, submitted drafts, `outcome.md`) that `/setup` Path A mines to calibrate `04-job-evaluation.md` and surface STAR candidates + +`/outcome` writes the data; `/setup` interprets it. This command never edits the evaluation framework or profile files itself. + +Follow these steps **in order**. + +--- + +## Step 0: Parse Input + +`$ARGUMENTS` may contain: + +- Nothing → list open applications and ask which one to update +- A company name (optionally with a role), e.g. `/outcome acme` or `/outcome acme ml engineer` → target that application + +--- + +## Step 1: Load State and Identify the Application + +1. Read `job_search_tracker.csv`. If it does not exist, create it with the standard header: + ``` + date,company,sector,role,role_type,channel,status,contact_person,fit_rating,notes,cv_file,cover_letter_file,source + ``` +2. **With an argument:** match rows case-insensitively on company (and role, if given). One match → proceed. Several → list them and ask. None → the application was made outside the workflow; collect company, role, date applied, channel, and posting URL from the user and add a tracker row. +3. **Without an argument:** list all rows whose status is not final (not hired / rejected / no response / withdrawn / offer declined) as a numbered table (company, role, date applied, current status) and ask which to update. If every row is resolved, say so and stop. +4. Derive the archive folder name: `documents/applications/_/` - lowercase, underscores for spaces (the convention documented in `documents/README.md`). Check whether the folder and an `outcome.md` already exist - if so, you are updating, not creating. + +--- + +## Step 2: Collect What Happened + +Ask the user what happened, then classify: + +**Progress updates** (application still open): +- Interview invitation / stage scheduled or completed (phone screen, technical, case, final round) +- Offer received (not yet accepted or declined) + +**Resolutions** (application closed) - these map to the status enum in `documents/README.md` that `/setup` parses: +- `hired` - accepted an offer +- `offer_declined` - received an offer, turned it down +- `rejected` - explicit rejection at any stage +- `no_response` - no reply; if the user is unsure whether to call it, note how long it has been since the last contact and let them decide - do not impose a cutoff +- `interview_only` - reached interviews but the process stalled or was abandoned without an explicit rejection + +Also collect, without interrogating - one or two open questions are enough: +- Dates for the stages reached +- Any feedback received, verbatim where the user remembers it +- What they'd do differently, and any signal about what the company valued (these feed `/setup`'s calibration and STAR-candidate mining, so concrete beats polished) + +--- + +## Step 3: Archive the Application Materials + +Create or update `documents/applications/_/`. All content here is personal data - the folder is already gitignored (`documents/applications/**`), so nothing needs redacting. + +1. **`cv_draft.tex` and `cover_letter.tex`** - copy (never move) the submitted files. Locate them via the tracker row's `cv_file`/`cover_letter_file` columns; if those are empty, look for `cv/main_.tex` and `cover_letters/cover__*.tex`. If a file already exists in the archive, leave it - the archived version is what was actually submitted. If no draft files exist (application made outside `/apply`), skip with a note. +2. **`job_posting.md`** - if it already exists, leave it. Otherwise try WebFetch on the tracker row's `source` URL and save the posting text. If the URL is dead (postings expire fast - this is exactly why the archive matters), ask the user to paste the posting, or write a stub noting the posting is unavailable. **Never reconstruct a posting from memory.** +3. **`outcome.md`** - write or update it in exactly the format documented in `documents/README.md`, so `/setup` Path A parses it without special cases: + +```markdown +# Outcome: + +**Status:** in_progress | hired | offer_declined | rejected | no_response | interview_only + +**Date resolved:** YYYY-MM-DD <- only when resolved; omit while in_progress + +## Interview stages reached +- [x] Phone screen (YYYY-MM-DD) +- [ ] Technical interview +- [ ] Case interview +- [ ] Final round +- [ ] Offer received + +## Notes + +``` + +Update rules: tick stage checkboxes as they are reached (add the date in parentheses), append dated entries to Notes, and only change `Status` from `in_progress` to a final value on resolution. Re-running `/outcome` on the same application is idempotent - it appends new information, never duplicates or rewrites history. + +--- + +## Step 4: Update the Tracker + +Update the matched row's `status` column (e.g. `applied` → `interview` → `offer` → `hired` / `rejected` / `no response` / `offer declined` / `withdrawn`) and append a short dated note to the `notes` column. Never restructure the CSV, reorder rows, or touch other rows. + +--- + +## Step 5: Calibration Handoff + +Count the `outcome.md` files under `documents/applications/` with a **final** status (not `in_progress`). + +- If 3 or more are resolved (or 2+ share a pattern - same role type rejected twice, same sector going silent), suggest: + > "You now have resolved applications on record. Run `/setup` (Path A) to fold them into your evaluation framework - it calibrates fit scoring from what actually got interviews, and mines your interview feedback for STAR examples." +- Do **not** write anything into `04-job-evaluation.md` or other skill files yourself. `/setup` Path A owns that merge - it is read-before-write and idempotent, and duplicating its logic here would race it. + +--- + +## Step 6: Confirm + +Summarize what was recorded: + +> **Outcome recorded for at .** +> +> - `documents/applications/_/outcome.md` - status: , +> - Archived: +> - Tracker: status → +> +> [Calibration suggestion from Step 5, if triggered] + +--- + +## Important Rules + +1. **Write data, don't interpret it.** The archive and tracker are the outputs; calibration belongs to `/setup`. This command never edits profile or framework files. +2. **The archived version is the submitted version.** Existing files in the application folder are never overwritten by fresher drafts. +3. **Never fabricate.** A dead posting URL gets a user-pasted copy or an explicit "unavailable" stub, not a reconstruction. Feedback is recorded as the user reports it. +4. **Stay schema-compatible.** `outcome.md` follows the format in `documents/README.md` exactly (`in_progress` is the one addition, for open applications); the tracker keeps its columns. +5. **Idempotent updates.** Re-running on the same application appends new stages and notes; it never duplicates folders, rows, or history. diff --git a/.claude/commands/setup.md b/.claude/commands/setup.md index a6380f5..375ffe7 100644 --- a/.claude/commands/setup.md +++ b/.claude/commands/setup.md @@ -104,7 +104,7 @@ Read each document found in Step A1. Process subfolders in this order: `cv/`, `l - `job_posting.md`: role title, company, required skills, experience level, sector, role type - `cover_letter.tex`: opening structure, body structure, bullet style, closing, recurring phrases - `cv_draft.tex`: profile statement, section ordering, framing for this role type -- `outcome.md`: status (hired/rejected/no_response/interview_only), interview stages, notes +- `outcome.md`: status (in_progress/hired/offer_declined/rejected/no_response/interview_only), interview stages, notes. Skip `in_progress` applications for calibration — they have no final signal yet. After reading, proceed to Step A4 without intermediate output. The user sees a complete picture in Step A6. diff --git a/README.md b/README.md index 52d2fb8..7c18e0c 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,9 @@ This runs the full workflow: evaluate fit, draft CV + cover letter, review with ## Other commands -`/setup`, `/scrape`, and `/apply` form the core workflow. Five more commands extend it once your profile is in place: +`/setup`, `/scrape`, and `/apply` form the core workflow. Six more commands extend it once your profile is in place: +- **`/outcome`** records what happened to an application - interview stages, offers, rejections, silence. It archives the submitted CV, cover letter, and posting text into `documents/applications/_/`, keeps `outcome.md` in the format `/setup` Path A parses, and updates the tracker. Once a few applications resolve, it points you back to `/setup` to calibrate the fit framework from what actually got interviews. - **`/rank`** bridges `/scrape` and `/apply`: it batch-scores all newly scraped postings against the fit framework (parallel agents fetch each posting and score the five evaluation dimensions) and returns a ranked shortlist with honest per-job strengths and gaps. Deal-breakers veto, deadlines get urgency flags, dead postings get marked expired. Pick a number and it hands off to the full `/apply` workflow. - **`/expand`** enriches your profile by scanning public sources you've already linked in it (GitHub repos, portfolio site, Kaggle, Google Scholar) and looking up syllabi for named courses and certifications. Discovered competencies are added to your profile with a source tag. Useful right after `/setup` to surface skills that documents alone don't make explicit. - **`/upskill`** analyzes the gap between your profile and your tracked job postings (or a single posting via `/upskill `). Produces a prioritized heatmap of skill gaps and a learning plan with web-searched study resources and time estimates. Useful for career planning between applications. @@ -122,6 +123,7 @@ ai-job-search/ │ │ ├── add-template.md # /add-template register custom LaTeX templates │ │ ├── add-portal.md # /add-portal generate a job-portal search skill for your market │ │ ├── rank.md # /rank triage scraped jobs into a ranked shortlist +│ │ ├── outcome.md # /outcome record application results, archive materials │ │ └── reset.md # /reset wipe profile data or documents folder │ ├── skills/ │ │ ├── job-application-assistant/ # Core application skill diff --git a/documents/README.md b/documents/README.md index ff9a701..5518e45 100644 --- a/documents/README.md +++ b/documents/README.md @@ -99,6 +99,8 @@ Reference letters from former managers, supervisors, or collaborators. A record of past job applications. Each subfolder is one application. +You can maintain these folders by hand, or let the **`/outcome`** command do it: it records progress updates and final results conversationally, archives the submitted drafts and the posting text, keeps `outcome.md` in the format below, and updates `job_search_tracker.csv` in the same step. + **Subfolder naming:** `_` — lowercase, underscores for spaces. Examples: @@ -122,7 +124,7 @@ applications/ ```markdown # Outcome: -**Status:** hired | offer_declined | rejected | no_response | interview_only +**Status:** in_progress | hired | offer_declined | rejected | no_response | interview_only **Date resolved:** YYYY-MM-DD @@ -139,6 +141,8 @@ What would you do differently? Any signal about what they valued or didn't? ``` +`in_progress` marks an application that is still open (used by `/outcome` for interview-stage updates before a resolution). `/setup`'s calibration draws conclusions only from applications with a final status. + **What `/setup` learns from outcome.md:** - Which role types and companies have led to interviews (signals strong fit areas) - Which applications did not progress (informs the experience match calibration in `04-job-evaluation.md`)