mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
feat: add /setup_docs, /reset, /expand commands and /upskill skill
Adds four contributions from @Michael-Bach: - /setup_docs - document-driven profile population from a documents/ folder (CV, LinkedIn export, diplomas, references, past applications). Idempotent merge with explicit additive vs. conflicting buckets and per-conflict prompts. - /reset - typed-RESET confirmation gate for clearing profile data and/or documents folder contents. - /expand - additive competency enrichment from documents and public URLs already in the profile (GitHub repos, portfolio sites), with web-searched syllabus lookups for named courses and certifications. - /upskill - skill-gap analysis vs tracked jobs (or single URL), produces a prioritized heatmap and learning plan with year-tagged WebSearch queries. Also adds the documents/ folder convention with README and gitignore entries for personal output files. Closes #6
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
# /expand - Competency Expansion from Documents and Online Presence
|
||||
|
||||
You are enriching the candidate profile by discovering competencies hidden in documents and public online presence. This command is additive only — it never modifies existing profile content, only extends it.
|
||||
|
||||
Follow these steps **exactly in order**. Do not skip steps.
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Read Existing Profile Files
|
||||
|
||||
Read these two files in parallel before doing anything else. You must know what is already there so you do not propose duplicates.
|
||||
|
||||
- `.claude/skills/job-application-assistant/01-candidate-profile.md`
|
||||
- `.claude/skills/job-application-assistant/02-behavioral-profile.md`
|
||||
|
||||
Hold this content in context throughout the command. Do not re-read these files later.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Discovery — Scan All Sources
|
||||
|
||||
Scan every available source for "experience items" — anything that implies skill, knowledge, or competency. Process sources in this order.
|
||||
|
||||
### 1a. documents/cv/
|
||||
Read all files in `documents/cv/`. Extract:
|
||||
- Every course or module listed (including university coursework and online courses)
|
||||
- Every certification mentioned, with issuer and date
|
||||
- Every job responsibility bullet point (tools, methods, outcomes)
|
||||
- Every independent project or side project
|
||||
- Every volunteer or extracurricular role
|
||||
|
||||
### 1b. documents/linkedin/
|
||||
Read all files in `documents/linkedin/`. Extract:
|
||||
- Courses and certifications in the "Licenses & Certifications" section
|
||||
- Skills and endorsements list
|
||||
- Volunteer experiences
|
||||
- Projects section
|
||||
- Any platform-specific items not already found in the CV
|
||||
|
||||
### 1c. documents/diplomas/
|
||||
Read all files in `documents/diplomas/`. Extract:
|
||||
- All course/module names listed on transcripts
|
||||
- Thesis title and subject area
|
||||
- Any specialisation or track name
|
||||
|
||||
### 1d. documents/references/
|
||||
Read all files in `documents/references/`. Extract:
|
||||
- Competency language used by the referee (what skills or qualities they mention)
|
||||
- Any specific projects, tools, or methods named
|
||||
|
||||
### 1e. GitHub Profile
|
||||
Look up the GitHub username from `01-candidate-profile.md`. If a GitHub URL or username is present:
|
||||
|
||||
1. Use WebFetch or WebSearch to retrieve the public profile and pinned repositories
|
||||
2. For each repository found:
|
||||
- Fetch the repository README
|
||||
- Note: name, description, primary language(s), topics/tags, any frameworks or libraries mentioned in the README
|
||||
3. Also retrieve the full repository list if available (to catch unpinned repos)
|
||||
|
||||
If no GitHub username or URL is found in the profile, skip this source and note it was skipped.
|
||||
|
||||
### 1f. Other URLs in Profile
|
||||
Check `01-candidate-profile.md` for any other URLs (portfolio site, personal website, Kaggle, Google Scholar, ResearchGate, publication links). For each:
|
||||
- Fetch the page
|
||||
- Extract any tools, methods, datasets, awards, or skills mentioned
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Web Enrichment
|
||||
|
||||
For each experience item discovered in Step 1, search the web to extract the competencies it implies. Apply both approaches below — do not choose one over the other.
|
||||
|
||||
### Approach A: Direct lookup (explicit tools and frameworks)
|
||||
If the item names a specific tool, framework, library, method, or platform, search for it directly:
|
||||
- `"[Course name] [Provider] syllabus learning outcomes"`
|
||||
- `"[Certification name] skills covered exam guide"`
|
||||
- `"[Tool/framework name] skills what you learn"`
|
||||
|
||||
Fetch the most relevant page and extract the competency list.
|
||||
|
||||
### Approach B: Inferred competencies (from description and context)
|
||||
For each item, regardless of whether Approach A found anything, also reason from the description:
|
||||
- What problem domain does this item address?
|
||||
- What methods, skills, or knowledge does someone need to do this work?
|
||||
- What is the standard toolchain for this kind of work?
|
||||
|
||||
Combine both approaches into a single competency list for each item.
|
||||
|
||||
### Prioritise web lookup for:
|
||||
- Named online courses (Coursera, edX, Udemy, LinkedIn Learning, DataCamp, fast.ai, etc.)
|
||||
- Named certifications (AWS, GCP, Azure, Databricks, Tableau, etc.)
|
||||
- University courses with a standard syllabus
|
||||
- GitHub repositories with a README that names specific technologies
|
||||
|
||||
### Infer (without web lookup) for:
|
||||
- Generic job responsibility bullets with no named tool
|
||||
- Vague project descriptions
|
||||
- Reference letter language (already phrased as competency — just record it)
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Build Competency Map
|
||||
|
||||
After enriching all items, build a deduplicated competency map. Group findings into these categories:
|
||||
|
||||
**Technical Skills — Primary** (core languages, frameworks, methods you use regularly)
|
||||
**Technical Skills — Secondary** (tools you have used but are not primary)
|
||||
**Domain Knowledge** (subject matter expertise: geophysics, ML, NLP, etc.)
|
||||
**Methods and Practices** (agile, version control, reproducibility, testing, etc.)
|
||||
**Soft / Behavioral** (leadership, communication, collaboration signals from references and project descriptions)
|
||||
|
||||
For each competency, record:
|
||||
- The competency name
|
||||
- The source item it came from (e.g. "Coursera — Deep Learning Specialisation", "GitHub — repo-name", "Reference letter — Jens Jensen")
|
||||
- Whether it came from direct lookup (A), inference (B), or both
|
||||
|
||||
Remove anything already present in `01-candidate-profile.md` or `02-behavioral-profile.md`.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Present Grouped Summary
|
||||
|
||||
Present all new competencies for the user's review before writing anything. Format:
|
||||
|
||||
```
|
||||
## /expand found [N] new competency signals across [M] sources
|
||||
|
||||
**COURSES & CERTIFICATIONS**
|
||||
Source: [Course/cert name — Provider]
|
||||
+ [Competency 1]
|
||||
+ [Competency 2]
|
||||
...
|
||||
|
||||
**GITHUB — [repo-name]**
|
||||
Source: README + inferred from tech stack
|
||||
+ [Competency 1]
|
||||
+ [Competency 2]
|
||||
...
|
||||
|
||||
**JOB RESPONSIBILITIES — [Company, Role]**
|
||||
Source: CV bullets + direct tool lookup
|
||||
+ [Competency 1]
|
||||
...
|
||||
|
||||
**BEHAVIORAL SIGNALS**
|
||||
Source: [Reference letter — Name / LinkedIn About / Project leadership]
|
||||
+ [Signal 1]
|
||||
...
|
||||
|
||||
[more sections as needed]
|
||||
```
|
||||
|
||||
Then ask:
|
||||
|
||||
> **How would you like to proceed?**
|
||||
>
|
||||
> - **`all`** — Add everything above to your profile
|
||||
> - **`review`** — I'll walk you through each source group one at a time
|
||||
> - **`skip`** — Cancel without writing anything
|
||||
>
|
||||
> Or list specific groups to skip (e.g. "skip GitHub, add everything else").
|
||||
|
||||
Wait for the user's response before writing anything.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Write Confirmed Additions
|
||||
|
||||
Apply only the confirmed items. Use the Edit tool to add to the relevant sections of each file — do not rewrite entire files.
|
||||
|
||||
### Additions to `01-candidate-profile.md`
|
||||
- Technical skills (primary and secondary) → append to the Technical Skills section
|
||||
- Domain knowledge → append to the Domain Knowledge or Technical Skills section (match the existing structure)
|
||||
- Methods and practices → append appropriately
|
||||
|
||||
For each addition, add a brief source annotation in a comment or parenthetical: *(Coursera — Deep Learning Specialisation)*, *(GitHub — project-name)*, etc. This makes future `/expand` runs idempotent.
|
||||
|
||||
### Additions to `02-behavioral-profile.md`
|
||||
- Soft/behavioral signals → append to the "Strongest Behavioral Traits" or "How I Work Best" section (match existing structure)
|
||||
- Always label inferred behavioral additions: *[Inferred from reference letter — Name / review before relying on this]*
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Summary Report
|
||||
|
||||
After writing, present:
|
||||
|
||||
```
|
||||
## /expand Complete
|
||||
|
||||
### Added to 01-candidate-profile.md
|
||||
[List each competency added, with source]
|
||||
|
||||
### Added to 02-behavioral-profile.md
|
||||
[List each behavioral signal added, with source]
|
||||
|
||||
### Sources processed
|
||||
[List each source scanned and how many competencies it yielded]
|
||||
|
||||
### Sources skipped
|
||||
[List any sources that were missing, empty, or yielded nothing new — with brief reason]
|
||||
|
||||
### Needs manual review
|
||||
[Any items that were ambiguous, partially readable, or where web lookup returned no clear syllabus]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
- **Additive only.** This command never modifies existing profile content. It only appends.
|
||||
- **Source-traceable.** Every addition records where it came from, so future runs are idempotent and the user can verify or remove individual items later.
|
||||
- **Both approaches, always.** Web lookup and inference are applied together — not as alternatives. A named course gets its official syllabus AND a reasoned competency list.
|
||||
- **User confirms before writing.** The full competency map is shown and confirmed before a single file is touched.
|
||||
- **Behavioral signals are labeled.** Anything inferred from tone, language, or indirect signals is marked as inferred so it is reviewed critically.
|
||||
- **GitHub is fully scanned.** All public repositories are checked, not just pinned ones — unpinned repos often contain significant competency signals.
|
||||
@@ -0,0 +1,227 @@
|
||||
# /reset - Reset Candidate Profile Data
|
||||
|
||||
You are resetting parts of the job search framework back to a blank state so the user can start fresh with `/setup` or `/setup_docs`.
|
||||
|
||||
**This command is destructive.** Nothing is deleted until the user explicitly confirms. Follow these steps exactly in order.
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Parse Scope from Arguments
|
||||
|
||||
Check `$ARGUMENTS` for a scope keyword:
|
||||
|
||||
- `profile` — clears candidate profile data from skill files only
|
||||
- `documents` — deletes user-provided files from the `documents/` folder only
|
||||
- `all` — both of the above
|
||||
|
||||
If `$ARGUMENTS` is empty or does not contain a recognized scope keyword, ask:
|
||||
|
||||
> **What would you like to reset?**
|
||||
>
|
||||
> - **`profile`** — Clears candidate data from the skill files (profile, behavioral, STAR examples, profile statements). The framework structure and writing rules are preserved. Use this to re-run `/setup` or `/setup_docs` from scratch.
|
||||
>
|
||||
> - **`documents`** — Deletes all files you've placed in the `documents/` folder (CV PDFs, LinkedIn export, diplomas, references, past applications). The folder structure and `README.md` are preserved.
|
||||
>
|
||||
> - **`all`** — Both of the above.
|
||||
>
|
||||
> Reply with `profile`, `documents`, or `all`.
|
||||
|
||||
Wait for the user's response before continuing.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Show Exactly What Will Be Cleared
|
||||
|
||||
Before doing anything, show the user precisely what will be wiped.
|
||||
|
||||
### If scope includes `profile`:
|
||||
|
||||
Read the current state of these files and report whether each has content or is already empty:
|
||||
|
||||
- `.claude/skills/job-application-assistant/01-candidate-profile.md`
|
||||
- `.claude/skills/job-application-assistant/02-behavioral-profile.md`
|
||||
- `.claude/skills/job-application-assistant/05-cv-templates.md` *(profile statements section only — framework structure is preserved)*
|
||||
- `.claude/skills/job-application-assistant/07-interview-prep.md` *(STAR examples and STAR candidates sections only — framework structure is preserved)*
|
||||
|
||||
Present as:
|
||||
|
||||
```
|
||||
## Profile reset will clear:
|
||||
|
||||
- 01-candidate-profile.md — [has content / already empty]
|
||||
Full file will be replaced with a blank template.
|
||||
|
||||
- 02-behavioral-profile.md — [has content / already empty]
|
||||
Full file will be replaced with a blank template.
|
||||
|
||||
- 05-cv-templates.md — [has profile statements / already blank]
|
||||
Profile statement templates will be cleared. LaTeX structure and tailoring guidelines are preserved.
|
||||
|
||||
- 07-interview-prep.md — [has STAR examples / already blank]
|
||||
STAR examples and any STAR candidate stubs will be cleared. Framework, tough questions, and roleplay guidelines are preserved.
|
||||
|
||||
The following files are NOT touched (they contain framework rules, not candidate data):
|
||||
- 03-writing-style.md
|
||||
- 04-job-evaluation.md
|
||||
- 06-cover-letter-templates.md
|
||||
```
|
||||
|
||||
### If scope includes `documents`:
|
||||
|
||||
Use Glob to list all files present in `documents/cv/`, `documents/linkedin/`, `documents/diplomas/`, `documents/references/`, and `documents/applications/`. Present as:
|
||||
|
||||
```
|
||||
## Documents reset will delete:
|
||||
|
||||
documents/cv/
|
||||
- [filename] or "(empty)"
|
||||
|
||||
documents/linkedin/
|
||||
- [filename] or "(empty)"
|
||||
|
||||
documents/diplomas/
|
||||
- [filename] or "(empty)"
|
||||
|
||||
documents/references/
|
||||
- [filename] or "(empty)"
|
||||
|
||||
documents/applications/
|
||||
- [subfolder/filename] or "(empty)"
|
||||
|
||||
documents/README.md — NOT deleted (instructions file)
|
||||
```
|
||||
|
||||
If all document subfolders are already empty, state "All document subfolders are already empty — nothing to delete." and skip the confirmation step for this scope.
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Require Explicit Confirmation
|
||||
|
||||
Present the confirmation prompt:
|
||||
|
||||
> **This cannot be undone.**
|
||||
>
|
||||
> Type **`RESET`** (all caps) to confirm, or anything else to cancel.
|
||||
|
||||
Wait for the user's response.
|
||||
|
||||
- If the user types exactly `RESET`: proceed to Step 3.
|
||||
- If the user types anything else: abort and tell them "Reset cancelled. Nothing was changed."
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Execute the Reset
|
||||
|
||||
### Profile reset
|
||||
|
||||
**For `01-candidate-profile.md`**, replace the file content with:
|
||||
|
||||
```markdown
|
||||
# Candidate Profile
|
||||
|
||||
<!-- Run /setup or /setup_docs to populate this file -->
|
||||
|
||||
## Identity
|
||||
|
||||
## Education
|
||||
|
||||
## Professional Experience
|
||||
|
||||
## Independent Projects
|
||||
|
||||
## Technical Skills
|
||||
|
||||
## Publications
|
||||
|
||||
## Awards
|
||||
|
||||
## References
|
||||
```
|
||||
|
||||
**For `02-behavioral-profile.md`**, replace the file content with:
|
||||
|
||||
```markdown
|
||||
# Behavioral Profile
|
||||
|
||||
<!-- Run /setup or /setup_docs to populate this file -->
|
||||
|
||||
## Overview
|
||||
|
||||
## Strongest Behavioral Traits
|
||||
|
||||
## How I Work Best
|
||||
|
||||
## Growth Areas
|
||||
|
||||
## Mapping to Job Posting Language
|
||||
|
||||
## Management Style Preferences
|
||||
|
||||
## Using This in Applications
|
||||
```
|
||||
|
||||
**For `05-cv-templates.md`**, locate the section that begins with `**Profile statement templates` and extends through the role-specific template blocks. Replace only that section with:
|
||||
|
||||
```markdown
|
||||
**Profile statement templates:**
|
||||
|
||||
<!-- Run /setup or /setup_docs to populate role-specific profile statements -->
|
||||
```
|
||||
|
||||
Leave all other content in `05-cv-templates.md` intact.
|
||||
|
||||
**For `07-interview-prep.md`**, locate and remove:
|
||||
- The entire `## Ready-Made STAR Examples` section and all numbered STAR examples under it
|
||||
- Any `## STAR Candidates (Complete Manually)` section added by `/setup_docs`
|
||||
|
||||
Replace with:
|
||||
|
||||
```markdown
|
||||
## Ready-Made STAR Examples
|
||||
|
||||
<!-- Run /setup or /setup_docs to populate STAR examples from your actual experience -->
|
||||
```
|
||||
|
||||
Leave all other content in `07-interview-prep.md` intact (STAR format explanation, tough questions, questions to ask interviewers, phone/video tips, follow-up etiquette, roleplay guidelines).
|
||||
|
||||
### Documents reset
|
||||
|
||||
For each non-empty document subfolder, delete all files within it using Bash `rm`. Do not delete the folder itself, and do not delete `documents/README.md`.
|
||||
|
||||
```bash
|
||||
rm -f documents/cv/*
|
||||
rm -f documents/linkedin/*
|
||||
rm -f documents/diplomas/*
|
||||
rm -f documents/references/*
|
||||
rm -rf documents/applications/*/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Confirm What Was Done and Next Steps
|
||||
|
||||
After the reset is complete, report:
|
||||
|
||||
```
|
||||
## Reset complete
|
||||
|
||||
### Cleared
|
||||
[List each file/folder that was actually modified or cleared]
|
||||
|
||||
### Unchanged
|
||||
[List anything that was already empty or was intentionally preserved]
|
||||
```
|
||||
|
||||
Then tell the user what to do next based on what was reset:
|
||||
|
||||
**If profile was reset:**
|
||||
> Your candidate profile is now blank. To repopulate it:
|
||||
> - Run `/setup_docs` if you have documents in the `documents/` folder — it will re-read them and rebuild the profile files.
|
||||
> - Run `/setup` for an interactive interview to fill in your profile from scratch.
|
||||
> - You can also run `/setup_docs` first, then `/setup` to fill in anything the documents didn't cover.
|
||||
|
||||
**If documents were reset:**
|
||||
> The `documents/` folder is now empty. Add your career documents and run `/setup_docs` to populate your profile. See `documents/README.md` for instructions on what to put where.
|
||||
|
||||
**If both were reset:**
|
||||
> Both your profile files and documents folder are now empty. Add documents to `documents/` and run `/setup_docs`, or run `/setup` for an interactive setup interview.
|
||||
@@ -0,0 +1,333 @@
|
||||
# /setup_docs - Document-Based Profile Population
|
||||
|
||||
You are populating the candidate skill files by reading from the user's `documents/` folder. This command complements `/setup` — it extracts structured data from real documents and merges it into the skill files. The interactive `/setup` command remains available for refinement afterward.
|
||||
|
||||
Read **all** existing skill files before writing anything. Match their exact style, tone, and structure.
|
||||
|
||||
Follow these steps **exactly in order**. Do not skip steps.
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Check for Documents
|
||||
|
||||
Check whether the `documents/` folder exists and contains files:
|
||||
|
||||
```
|
||||
documents/cv/
|
||||
documents/linkedin/
|
||||
documents/diplomas/
|
||||
documents/references/
|
||||
documents/applications/
|
||||
```
|
||||
|
||||
Use Glob to check each subfolder for any files. If the `documents/` folder is missing entirely, or all subfolders are empty, stop and tell the user:
|
||||
|
||||
> **No documents found.**
|
||||
>
|
||||
> Create a `documents/` folder at the root of this repo and add your career documents to it. The expected structure is:
|
||||
>
|
||||
> ```
|
||||
> documents/
|
||||
> ├── cv/ ← Your master CV (PDF or .tex)
|
||||
> ├── linkedin/ ← LinkedIn profile export (PDF via Save to PDF)
|
||||
> ├── diplomas/ ← Degree certificates (PDF)
|
||||
> ├── references/ ← Reference letters (PDF, .txt, or .md)
|
||||
> └── applications/
|
||||
> └── <company>_<role>/
|
||||
> ├── job_posting.md
|
||||
> ├── cover_letter.tex
|
||||
> ├── cv_draft.tex
|
||||
> └── outcome.md
|
||||
> ```
|
||||
>
|
||||
> See `documents/README.md` for full instructions. Once you've added documents, re-run `/setup_docs`.
|
||||
|
||||
If at least one subfolder has files, continue.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Inventory
|
||||
|
||||
Scan the full `documents/` tree and print a clear inventory of what was found. Use Glob with `documents/**/*` to list all files.
|
||||
|
||||
Present the inventory as:
|
||||
|
||||
```
|
||||
## Documents Found
|
||||
|
||||
**cv/**: [list files, or "empty"]
|
||||
**linkedin/**: [list files, or "empty"]
|
||||
**diplomas/**: [list files, or "empty"]
|
||||
**references/**: [list files, or "empty"]
|
||||
**applications/**: [list subfolders with their files, or "empty"]
|
||||
|
||||
I will now read these documents and cross-reference their content before proposing any changes to the skill files.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Read All Existing Skill Files
|
||||
|
||||
Before extracting anything, read the current state of all seven skill files. This is required to make the merge intelligent — you must know what's already there before proposing additions or flagging conflicts.
|
||||
|
||||
Read all of these in parallel:
|
||||
- `.claude/skills/job-application-assistant/01-candidate-profile.md`
|
||||
- `.claude/skills/job-application-assistant/02-behavioral-profile.md`
|
||||
- `.claude/skills/job-application-assistant/03-writing-style.md`
|
||||
- `.claude/skills/job-application-assistant/04-job-evaluation.md`
|
||||
- `.claude/skills/job-application-assistant/05-cv-templates.md`
|
||||
- `.claude/skills/job-application-assistant/06-cover-letter-templates.md`
|
||||
- `.claude/skills/job-application-assistant/07-interview-prep.md`
|
||||
|
||||
Hold this content in context throughout the rest of the command. Do not re-read these files later.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Parse Documents
|
||||
|
||||
Read each document found in Step 1. Process subfolders in this order: `cv/` → `linkedin/` → `diplomas/` → `references/` → `applications/`.
|
||||
|
||||
For each document type, extract the following:
|
||||
|
||||
### cv/ documents
|
||||
- Full name, contact information (email, phone, LinkedIn, GitHub)
|
||||
- Education entries: degree, institution, dates, thesis topic
|
||||
- Work experience: title, company, dates, location, bullet points
|
||||
- Skills and technologies
|
||||
- Publications and awards
|
||||
- Any profile statement or summary section
|
||||
|
||||
### linkedin/ documents
|
||||
- About/summary section (full text — used for behavioral inference)
|
||||
- Work experience: title, company, dates, description bullets
|
||||
- Education entries
|
||||
- Skills and endorsements list
|
||||
- Certifications and licenses
|
||||
- Volunteer work
|
||||
- Publications
|
||||
- Recommendations received (full text — used for behavioral inference and reference enrichment)
|
||||
|
||||
If multiple LinkedIn exports are present, use the most recently modified file and note the others were skipped.
|
||||
|
||||
### diplomas/ documents
|
||||
- Official degree title and level
|
||||
- Institution name (official spelling)
|
||||
- Graduation date
|
||||
- Any grade, distinction, or GPA if visible
|
||||
|
||||
### references/ documents
|
||||
- Referee name, title, organization
|
||||
- Full text of the letter (extract specific quotes)
|
||||
- Competency language used (phrases that describe how you work)
|
||||
|
||||
### applications/ subfolders
|
||||
For each `<company>_<role>/` subfolder, read whichever files are present:
|
||||
|
||||
**`job_posting.md`**: Extract role title, company, required skills, experience level, key responsibilities. Note the sector and role type.
|
||||
|
||||
**`cover_letter.tex`**: Extract the opening paragraph structure, the body paragraph structure, the bullet list style, the closing. Note recurring phrases or framings.
|
||||
|
||||
**`cv_draft.tex`**: Extract the profile statement used, section ordering, and how experience was framed for this role type.
|
||||
|
||||
**`outcome.md`**: Extract status (hired/rejected/no_response/interview_only), interview stages reached, and any notes.
|
||||
|
||||
After reading all documents, proceed to Step 4 without presenting intermediate output. You will present a complete picture in Step 5.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Cross-Reference Check
|
||||
|
||||
Before mapping anything to skill files, check for inconsistencies across documents. Look for:
|
||||
|
||||
- **Date mismatches**: Does the CV show the same start/end dates for each role as LinkedIn? As the diploma?
|
||||
- **Title mismatches**: Does the job title in the CV match LinkedIn for the same role?
|
||||
- **Education mismatches**: Does the degree name and graduation date match across CV, diploma, and LinkedIn?
|
||||
- **Employer name variations**: Is the same company spelled differently across documents?
|
||||
|
||||
If inconsistencies are found, present them now as a numbered list before proceeding:
|
||||
|
||||
```
|
||||
## Cross-Reference Issues Found
|
||||
|
||||
These inconsistencies need to be resolved before I continue. For each one, tell me which version is correct:
|
||||
|
||||
1. **Role title mismatch — [COMPANY_NAME]:**
|
||||
CV says: "[TITLE_A]"
|
||||
LinkedIn says: "[TITLE_B]"
|
||||
Which is correct?
|
||||
|
||||
2. [next issue]
|
||||
```
|
||||
|
||||
Wait for the user to resolve all cross-reference issues before continuing to Step 5. If no inconsistencies are found, state "No cross-reference issues found." and continue immediately.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Build Change Sets
|
||||
|
||||
For each skill file, compare the extracted document content against the current skill file content from Step 2. Build two buckets of proposed changes:
|
||||
|
||||
### Additive changes
|
||||
Content that is entirely new — not present in the skill file in any form. Examples:
|
||||
- A certification that doesn't appear anywhere in `01-candidate-profile.md`
|
||||
- A new skill keyword from LinkedIn endorsements not in the skills section
|
||||
- A volunteer entry not mentioned anywhere
|
||||
- A referee not currently listed in the references section
|
||||
- A new behavioral quote from a reference letter
|
||||
- A new award
|
||||
|
||||
### Conflicting changes
|
||||
Content that touches something already in a skill file but disagrees with it. Examples:
|
||||
- A different date range for an existing job entry
|
||||
- A different job title for the same role
|
||||
- A bullet describing a role in a way that contradicts the existing description
|
||||
- A diploma showing a different graduation date than what's recorded
|
||||
|
||||
**Inference rules — apply these when populating files from inferred sources:**
|
||||
|
||||
**For `02-behavioral-profile.md` (behavioral inference):**
|
||||
- Source: LinkedIn About section, recommendation letters
|
||||
- Extract: recurring themes, adjectives used to describe you, phrases about how you work
|
||||
- Only add to sections like "Strongest Behavioral Traits", "How [Candidate] Works Best", or "Management Style Preferences". Do not overwrite or supplement any existing scored assessments or competency tables already in the file — treat those as authoritative.
|
||||
- Always label inferred additions clearly: *[Inferred from LinkedIn About / Reference letter — review before relying on this]*
|
||||
|
||||
**For `03-writing-style.md` (style inference from cover letters):**
|
||||
- Source: `cover_letter.tex` files in `applications/`
|
||||
- Extract: recurring structural patterns, opening paragraph styles, any phrases that appear across multiple letters
|
||||
- Add these as observations under a new section "## Patterns Observed in Past Applications" — do not modify existing rules
|
||||
- Only add if at least 2 cover letters are present and a genuine pattern is visible
|
||||
|
||||
**For `04-job-evaluation.md` (calibration from past applications):**
|
||||
- Source: `job_posting.md` + `outcome.md` pairs
|
||||
- If an application reached interview stage or resulted in an offer: note the role type and sector as a confirmed strong-fit signal
|
||||
- If an application received no response or rejection: note only if the pattern repeats across 2+ applications (single data points are noise)
|
||||
- Add findings under a new section "## Calibration from Past Applications" — do not modify existing scoring framework
|
||||
|
||||
**For `05-cv-templates.md` (profile statement extraction):**
|
||||
- Source: `cv_draft.tex` files in `applications/`
|
||||
- Extract any profile statement that doesn't already appear in the templates file
|
||||
- Add it under the appropriate role type heading with a label: *[Used for: <company>_<role>]*
|
||||
|
||||
**For `06-cover-letter-templates.md` (structure extraction from past letters):**
|
||||
- Source: `cover_letter.tex` files in `applications/`
|
||||
- Extract: opening paragraph patterns, bullet list structures, closing formulations
|
||||
- Add only what is structurally distinct from the existing templates
|
||||
|
||||
**For `07-interview-prep.md` (STAR candidates from achievements):**
|
||||
- Source: CV bullets, LinkedIn descriptions, reference letter quotes
|
||||
- Identify achievements not yet covered by an existing STAR example
|
||||
- Do NOT draft full STAR examples — instead, add a stub under a new section "## STAR Candidates (Complete Manually)":
|
||||
|
||||
```markdown
|
||||
### [Achievement title]
|
||||
**Source:** [CV / LinkedIn / Reference letter — role/company]
|
||||
**What happened:** [one sentence summary of the achievement]
|
||||
**Why it matters:** [which interview question types this could answer]
|
||||
**S/T/A/R stub:**
|
||||
- Situation:
|
||||
- Task:
|
||||
- Action:
|
||||
- Result:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Present and Confirm Changes
|
||||
|
||||
Present the full change set before writing anything. Structure the presentation by skill file.
|
||||
|
||||
### Additive changes
|
||||
|
||||
Show all additive changes in a single grouped list, organized by target file:
|
||||
|
||||
```
|
||||
## Proposed Additive Changes
|
||||
|
||||
These are new items not currently in the skill files. They will be added exactly as shown.
|
||||
|
||||
### 01-candidate-profile.md
|
||||
- [ ] New certification: [title], [issuer], [date] — extracted from LinkedIn
|
||||
- [ ] New reference: [name, title, company] — extracted from reference letter
|
||||
Quote: "[relevant quote]"
|
||||
|
||||
### 02-behavioral-profile.md
|
||||
- [ ] New behavioral observation [labeled as inference]: "[phrase from LinkedIn About]"
|
||||
|
||||
[...and so on for each file with additive changes]
|
||||
```
|
||||
|
||||
Then ask:
|
||||
|
||||
> **Apply all additive changes?** These add new content without touching anything already in the files.
|
||||
> Reply **yes** to apply all, or list the numbers you want to skip.
|
||||
|
||||
Wait for the user's response before proceeding. Apply only the confirmed items.
|
||||
|
||||
### Conflicting changes
|
||||
|
||||
Present each conflict individually, one at a time:
|
||||
|
||||
```
|
||||
## Conflict 1 of [N]: Job title — [COMPANY_NAME]
|
||||
|
||||
**Current in 01-candidate-profile.md:**
|
||||
[TITLE_A] — [COMPANY_NAME] ([START]–[END])
|
||||
|
||||
**Proposed (from LinkedIn export):**
|
||||
[TITLE_B] — [COMPANY_NAME] ([START]–[END])
|
||||
|
||||
Options:
|
||||
[keep] Keep the existing text
|
||||
[replace] Replace with the version from the document
|
||||
[manual] I'll edit this myself — skip for now
|
||||
```
|
||||
|
||||
Wait for the user's choice on each conflict before presenting the next one.
|
||||
|
||||
If there are no conflicts, state "No conflicting changes found." and skip this section.
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Write Confirmed Changes
|
||||
|
||||
After all confirmations are collected, apply the changes. Edit each affected skill file using the Edit tool, making targeted changes only. Do not rewrite entire files.
|
||||
|
||||
For each file edited, state which changes were applied.
|
||||
|
||||
If a skill file has no confirmed changes, state "No changes made to [filename]."
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Summary Report
|
||||
|
||||
After all writes are complete, present the full summary:
|
||||
|
||||
```
|
||||
## /setup_docs Complete
|
||||
|
||||
### What was populated
|
||||
[For each skill file that received changes, list what was added or updated]
|
||||
|
||||
### What was skipped
|
||||
[List any documents that were present but yielded no new information — with a brief reason]
|
||||
|
||||
### Needs manual attention
|
||||
[List any gaps, ambiguous inferences, STAR stubs, or items flagged during cross-reference resolution]
|
||||
|
||||
### Next steps
|
||||
- Review the STAR stubs in `07-interview-prep.md` and complete them with specific actions and results
|
||||
- Run `/setup` at any time for an interactive interview to refine sections that documents can't fully populate (behavioral profile depth, career goals, salary expectations)
|
||||
- Run `/apply <job posting URL>` to generate your first tailored application
|
||||
- Re-run `/setup_docs` whenever you add new documents to the `documents/` folder
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
- **Read before write.** All skill files are read before any changes are proposed. This makes every run idempotent — changes already present will not be proposed again.
|
||||
- **Two-bucket merge.** Additive changes (low risk) get a single bulk confirmation. Conflicts (high risk) get individual decisions. This minimizes friction without sacrificing control.
|
||||
- **Inference is labeled.** When populating behavioral or style files from inferred sources (tone analysis, pattern extraction), the inserted content is always labeled as inferred so it can be reviewed critically before being relied on.
|
||||
- **Graceful degradation.** Empty subfolders are noted but do not cause errors. The command works with whatever documents are present.
|
||||
- **Past applications as signal.** outcome.md data is treated as calibration input to `04-job-evaluation.md`, not as hard overrides. Single data points are not extrapolated.
|
||||
- **Never fabricate.** If a document is ambiguous or partially readable, flag it for manual review rather than inferring content that may be wrong.
|
||||
@@ -5,7 +5,7 @@
|
||||
"Bash(python3:*)",
|
||||
"Bash(python:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(bun:*)"
|
||||
"Bash(bun:*)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
# Upskill
|
||||
|
||||
**name:** upskill
|
||||
**description:** Compares tracked job postings against the candidate profile to identify skill gaps and generate a prioritized learning plan with study resources. Triggers on: /upskill, upskill, skill gaps, what should I learn, learning plan
|
||||
**allowed-tools:** Read, Write, Glob, Grep, WebFetch, WebSearch
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
`/upskill` analyses jobs you have tracked and your current profile to identify skill gaps, then produces a heatmap of those gaps and a learning plan with concrete, web-searched study resources and a recommended study order.
|
||||
|
||||
## Invocation
|
||||
|
||||
- **`/upskill`** — aggregate mode: analyses all jobs in `job_search_tracker.csv`
|
||||
- **`/upskill <URL>`** — targeted mode: analyses a single job posting fetched from the URL
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Detect Mode
|
||||
|
||||
Check whether the user provided a URL argument:
|
||||
|
||||
- If the invocation was `/upskill` with no argument → **aggregate mode**
|
||||
- If the invocation was `/upskill <URL>` → **targeted mode**, store the URL for Step 2
|
||||
|
||||
In targeted mode, derive a slug from the job title and company for the report filename (e.g. `guardsix-senior-ai-engineer`). You will fetch the posting in Step 2.
|
||||
|
||||
## Step 2: Load Data
|
||||
|
||||
### Aggregate mode
|
||||
1. Read `job_search_tracker.csv`. Extract all rows. The columns are:
|
||||
`date, company, sector, role, role_type, channel, status, contact_person, fit_rating, notes, cv_file, cover_letter_file, source`
|
||||
2. For each row, note the `role`, `company`, and `fit_rating`. The `fit_rating` column is a 0–100 score where 100 = perfect fit. You will use it to weight gaps — a lower fit rating means the role exposed more gaps.
|
||||
3. Read `.claude/skills/job-application-assistant/01-candidate-profile.md` to get the candidate's current skills and experience.
|
||||
4. Check `upskill/` for the most recent aggregate report file (`report-YYYY-MM-DD.md`) — if one exists, note its date and load it for the diff in Step 8.
|
||||
|
||||
### Targeted mode
|
||||
1. Use WebFetch to retrieve the job posting from the URL.
|
||||
2. Extract: job title, company, required skills, preferred skills, responsibilities, and any domain context.
|
||||
3. Read `.claude/skills/job-application-assistant/01-candidate-profile.md` for the candidate's current skills.
|
||||
4. No tracker data is used in targeted mode.
|
||||
|
||||
## Step 3: Pass 1 — Hard Skill Diff
|
||||
|
||||
Extract required and preferred technical skills from each job source:
|
||||
|
||||
### Aggregate mode
|
||||
For each job row in the tracker, you do not have the full posting — use the `role`, `sector`, and `notes` columns to infer likely required skills. If the row has a `source` URL, you may optionally WebFetch it for more detail, but skip if the URL is missing or dead.
|
||||
|
||||
Build a **skill frequency map**: for each extracted skill, count how many jobs mention it. Then apply a **fit weight**: for each job, multiply the skill count contribution by `(100 - fit_rating) / 100` — lower fit jobs contribute more to the gap score.
|
||||
|
||||
Final score for each skill: `sum of (fit_weight × occurrence)` across all jobs.
|
||||
|
||||
### Targeted mode
|
||||
Extract the explicit required and preferred skills from the fetched posting. Each skill gets equal weight (no fit weighting needed since there is only one job). List required skills before preferred skills, then sort alphabetically within each group.
|
||||
|
||||
### Diff against profile
|
||||
Remove any skill from the list that is already present in the candidate profile (`01-candidate-profile.md`). Be generous — if the profile mentions a skill in any form (e.g. "Python" covers "Python scripting"), remove it.
|
||||
|
||||
What remains is the **hard skill gap list**. In aggregate mode, rank by score descending. In targeted mode, list required skill gaps before preferred skill gaps, then sort alphabetically within each group.
|
||||
|
||||
## Step 4: Pass 2 — LLM Synthesis
|
||||
|
||||
Now reason holistically about gaps that the hard skill diff would miss. Consider:
|
||||
|
||||
- **Domain knowledge gaps**: Does the candidate lack familiarity with the industry, domain, or problem space the jobs operate in? (e.g. cybersecurity, climate tech, quantitative finance)
|
||||
- **Soft skill gaps**: Do the job descriptions emphasise ways of working, communication styles, or leadership expectations that the profile does not address?
|
||||
- **Tooling and process gaps**: Frameworks, cloud services, methodologies (e.g. MLOps practices, CI/CD, agile at scale) that appear across jobs but are absent from the profile
|
||||
- **Credential or certification gaps**: If multiple postings list a certification as preferred, flag it
|
||||
|
||||
Tag each synthesised gap as one of: `[domain]`, `[soft]`, `[tooling]`, or `[credential]`.
|
||||
|
||||
Do not duplicate gaps already captured in Pass 1. Only add what was missed.
|
||||
|
||||
In targeted mode, treat all synthesised gaps as arising from a single posting. Credential gaps can still be flagged if the single posting lists them as preferred or required.
|
||||
|
||||
## Step 5: Build Gap Heatmap
|
||||
|
||||
Combine Pass 1 and Pass 2 results into a single prioritised table. Assign priority as follows:
|
||||
|
||||
- **Critical**: Hard skills with high frequency/weight scores, or domain gaps that appear across most tracked jobs
|
||||
- **High**: Hard skills with moderate scores, or soft/tooling gaps that appear consistently
|
||||
- **Medium**: Lower-frequency hard skills, or synthesised gaps that appeared in fewer roles
|
||||
- **Low**: One-off mentions or minor nice-to-haves
|
||||
|
||||
Format:
|
||||
|
||||
| Priority | Skill / Area | Type | Gap Source |
|
||||
|----------|-------------|------|------------|
|
||||
| Critical | Kubernetes | Hard | 4/5 jobs, score 3.2 |
|
||||
| High | Security domain knowledge | Domain | LLM synthesis |
|
||||
| High | CI/CD pipelines | Tooling | LLM synthesis |
|
||||
| Medium | AWS (advanced) | Hard | 2/5 jobs, score 1.1 |
|
||||
| Low | ... | ... | ... |
|
||||
|
||||
Print this table to the terminal as an intermediate output before continuing to the learning plan.
|
||||
|
||||
In targeted mode, assign priority based on the job's own language: required skills → Critical or High, preferred skills → Medium, inferred gaps from LLM synthesis → Medium or Low.
|
||||
|
||||
## Step 6: Build Learning Plan
|
||||
|
||||
For every **Critical** and **High** gap (and **Medium** gaps if fewer than 5 total gaps exist), produce a learning entry.
|
||||
|
||||
### For each gap:
|
||||
|
||||
1. **Run a WebSearch** to find current, highly-rated study resources. Use queries like:
|
||||
- `"best Kubernetes course 2025 site:reddit.com OR coursera.org OR fast.ai OR missing.csail.mit.edu"`
|
||||
- `"learn [skill] for [domain] 2025 recommendations"`
|
||||
Include the current year in the query to avoid stale results.
|
||||
|
||||
2. **Pick 2-3 resources** from the search results. Prefer:
|
||||
- Courses with hands-on labs over lecture-only content
|
||||
- Official documentation for tooling gaps
|
||||
- Books for domain knowledge gaps
|
||||
- For each resource: name, URL, and one-line reason why it fits
|
||||
|
||||
3. **Write a study direction** tailored to the candidate's existing background. For example: if the candidate knows Docker, say "Skip the containers basics module — go straight to the orchestration and networking sections." Be specific about what to skip and where to start.
|
||||
|
||||
4. **Estimate time to working proficiency** (e.g. "~20h", "~40h for a solid foundation"). Be realistic — err toward more rather than less.
|
||||
|
||||
### Group by theme
|
||||
|
||||
Group entries under theme headings rather than listing alphabetically. Example themes: Cloud & Infrastructure, MLOps, Domain Knowledge, Security, Soft Skills & Ways of Working, Certifications.
|
||||
|
||||
Example entry format:
|
||||
|
||||
```
|
||||
### Cloud & Infrastructure
|
||||
|
||||
**Kubernetes** `[Hard]` — ~20h
|
||||
- [Kubernetes for Absolute Beginners – KodeKloud](https://kodekloud.com) — hands-on labs, widely recommended on r/kubernetes for practical learners
|
||||
- [Official Kubernetes Docs: Concepts](https://kubernetes.io/docs/concepts/) — use as reference once you have the basics
|
||||
- [The Kubernetes Book – Nigel Poulton](https://leanpub.com/the-kubernetes-book) — concise, updated annually
|
||||
|
||||
Study direction: You already know Docker and containerisation — skip Chapter 1 on containers. Start at Pod scheduling and work through Services and Deployments. Focus on manifests and `kubectl` fluency before touching Helm.
|
||||
```
|
||||
|
||||
## Step 7: Suggest Study Order
|
||||
|
||||
After the learning plan, add a **Suggested Study Order** section. Number the topics in the recommended sequence. Apply these rules:
|
||||
|
||||
1. **Dependencies first**: If learning topic B requires topic A (e.g. "AWS networking" requires "AWS fundamentals"), place A before B and note the dependency.
|
||||
2. **Critical before High before Medium**: Within a dependency tier, prioritise by gap priority.
|
||||
3. **Quick wins early**: If a Medium gap is very fast (~5h) and boosts confidence, it can be placed early.
|
||||
4. **Domain knowledge last**: Domain/soft gaps usually benefit from being studied alongside practical projects rather than up front.
|
||||
|
||||
Format:
|
||||
|
||||
```
|
||||
## Suggested Study Order
|
||||
|
||||
| # | Topic | Type | Est. Time | Note |
|
||||
|---|-------|------|-----------|------|
|
||||
| 1 | Kubernetes | Hard | ~20h | Required before AWS EKS in step 3 |
|
||||
| 2 | CI/CD pipelines | Tooling | ~10h | |
|
||||
| 3 | AWS (advanced) | Hard | ~25h | Builds on step 1 |
|
||||
| 4 | Security domain knowledge | Domain | ~15h | Study alongside a real project |
|
||||
|
||||
**Total estimated time: ~70h**
|
||||
```
|
||||
|
||||
## Step 8: Write and Save Report
|
||||
|
||||
### Compose the report
|
||||
|
||||
Assemble the full report in this order:
|
||||
|
||||
```markdown
|
||||
# Upskill Report — YYYY-MM-DD
|
||||
**Mode:** Aggregate (N jobs analysed) | Targeted: <Job Title> @ <Company>
|
||||
|
||||
---
|
||||
|
||||
## Since Last Report
|
||||
<!-- Aggregate mode only. Omit section entirely in targeted mode or if no previous report exists. -->
|
||||
**Gaps closed** (skills added to profile since <previous date>):
|
||||
- ...
|
||||
|
||||
**New gaps** (from jobs tracked since <previous date>):
|
||||
- ...
|
||||
|
||||
---
|
||||
|
||||
## Gap Heatmap
|
||||
|
||||
| Priority | Skill / Area | Type | Gap Source |
|
||||
|----------|-------------|------|------------|
|
||||
...
|
||||
|
||||
---
|
||||
|
||||
## Learning Plan
|
||||
|
||||
### <Theme>
|
||||
|
||||
**<Skill>** `[Type]` — ~Xh
|
||||
- [Resource 1](url) — reason
|
||||
- [Resource 2](url) — reason
|
||||
|
||||
Study direction: ...
|
||||
|
||||
---
|
||||
|
||||
## Suggested Study Order
|
||||
|
||||
| # | Topic | Type | Est. Time | Note |
|
||||
...
|
||||
|
||||
**Total estimated time: ~Xh**
|
||||
```
|
||||
|
||||
### Save the report
|
||||
|
||||
- **Aggregate:** `upskill/report-YYYY-MM-DD.md`
|
||||
- **Targeted:** `upskill/report-YYYY-MM-DD-<company-slug>-<role-slug>.md`
|
||||
- Slugify: lowercase, spaces → hyphens, strip special characters
|
||||
- Example: `upskill/report-2026-04-20-guardsix-senior-ai-engineer.md`
|
||||
|
||||
Use the Write tool to save the file.
|
||||
|
||||
### Diff section (aggregate mode only)
|
||||
|
||||
If a previous aggregate report was loaded in Step 2:
|
||||
- **Gaps closed**: Any skill in the previous report's heatmap that is now present in the candidate profile
|
||||
- **New gaps**: Any skill in the current heatmap that was not in the previous report
|
||||
|
||||
If no previous report exists, omit the "Since Last Report" section entirely.
|
||||
|
||||
### Confirm to user
|
||||
|
||||
After saving, print:
|
||||
> "Report saved to `upskill/<filename>.md`. Review it anytime to track your learning progress."
|
||||
|
||||
## Important Rules
|
||||
|
||||
1. **Never fabricate resources.** Only cite resources found via actual WebSearch results. Do not invent course names, URLs, or authors.
|
||||
2. **Search with the current year.** Include the year in every WebSearch query for resources so results stay fresh.
|
||||
3. **Targeted mode ignores the tracker.** In targeted mode, analyse only the fetched posting. Do not load or reference `job_search_tracker.csv`.
|
||||
4. **Be generous with profile matching.** If a skill appears in the candidate profile in any form, do not flag it as a gap. Avoid false positives.
|
||||
5. **Print the heatmap before the learning plan.** Always show the intermediate heatmap table in the terminal before proceeding to resource search, so the user can see what you are working from.
|
||||
6. **Omit Low-priority gaps from the learning plan.** List them in the heatmap for completeness, but do not generate study resources for them unless the user asks.
|
||||
7. **Always save the report.** Do not skip the Write step even if the user seems satisfied with the terminal output.
|
||||
Reference in New Issue
Block a user