Skip to content
Productivity
Command

/outcome

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:

From plugin
madslorentzen-ai-job-search
31k12 skills1 agent12 commands
Install
$ npx -y skills add MadsLorentzen/ai-job-search --agent claude-code

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/outcome

Context preview

What this command does when you run it.

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:

Command definition

outcome.md

/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/<company>_<role>/` - 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.

The command also owns the stretch *before* there is an outcome to record: the **follow-up branch** (Step 2b) surfaces open applications that have gone quiet, drafts a brief follow-up note in the user's voice, and logs it - so the chase and the resolution it eventually leads to live in one flow.

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
  • `followup` → enter the follow-up branch (Step 2b) over every quiet open application, using the default threshold of **10 days**
  • `followup <N>`, e.g. `/outcome followup 14` → follow-up branch with an N-day threshold
  • `followup <company>`, e.g. `/outcome followup acme` → draft a follow-up for that application now, regardless of threshold

---

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 (see **Tracker status vocabulary** below) as a numbered table (company, role, date applied, current status, days quiet, follow-ups sent) and ask which to update. The two derived columns come straight from existing data: **days quiet** counts from the row's `date` or the latest dated entry in `notes`, whichever is more recent; **follow-ups sent** counts the `followed up YYYY-MM-DD` markers in `notes`. If any open row is 10+ days quiet with fewer than two follow-ups sent, add one line under the table: "Some of these have gone quiet - want a follow-up draft? (Step 2b)". If every row is resolved, say so and stop.

**`drafted` rows are listed but never counted as quiet** - nothing was sent, so nobody is late replying. List them under their own heading ("Drafted, not yet submitted"), leave **days quiet** and **follow-ups sent** blank, and keep them out of the follow-up offer above. 4. Derive the archive folder name: `documents/applications/<company>_<role>/` - 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.

---

Tracker status vocabulary

Canonical spellings for the tracker CSV `status` column (underscores, never spaces):

`drafted` | `applied` | `interview` | `offer` | `hired` | `rejected` | `no_response` | `offer_declined` | `withdrawn`

  • **Final** (application closed): `hired`, `rejected`, `no_response`, `offer_declined`, `withdrawn`
  • **Open**: everything else, `drafted` included — a row is active until its status is one of the **Final** values.
  • **`drafted`** is open but distinct — nothing was sent, so no follow-up is ever due.
  • Readers must also accept the legacy space spellings `no response` and `offer declined` on read, so that existing trackers keep working without a migration. Never write them — they are the same values as `no_response` and `offer_declined`, not separate statuses, equally **Final**, and every rule that names one applies to the other.

> Distinct from the archive `Status:` enum in `documents/README.md` > (`in_progress` | `hired` | `offer_declined` | `rejected` | `no_response` | `interview_only`), > which describes the per-application `outcome.md` file, not this column. The two enums > are never written to the same field.

---

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 archive `Status:` enum in `documents/README.md` that `/setup` parses (distinct from the tracker CSV column; see **Tracker status vocabulary** above):

  • `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 2b: Follow-Up Branch (chase a quiet application)

Enter this branch from the `followup` argument (Step 0) or from the

Read more
Ships withmadslorentzen-ai-job-search

The job search that runs on your machine. An AI-powered job application framework built on Claude Code. Fork it, fill in your profile, and let Claude evaluate job postings, tailor your CV, write cover letters, and prepare you for interviews.

Get the whole plugin

Other commands on madslorentzen-ai-job-search.