JobOps Workspace Setup
This skill initializes or reconfigures a JobOps workspace. It writes a single
user-owned config file at .jobops/config.json, creates the output directory
tree, installs templates from the plugin into the workspace, updates
.gitignore, and offers optional career-history import and legacy-file migration.
Flags:
--reconfigure— re-run setup against an existing workspace; prompts before overwriting anything.--skip-migration— skip the legacy-file migration step (Step 9) unconditionally.--skip-history— skip the optional career-history import (Step 8).
Step 1: Welcome and existing-config check
If .jobops/config.json already exists, read it and present three choices:
- Reconfigure all — walk the full interview; overwrite at the end.
- Reconfigure specific sections — directories only / preferences only / candidate (contact details) only / templates only / migration only.
- Exit — leave everything as-is.
If --reconfigure was passed, skip the prompt and go straight to option 1.
If no config exists, proceed to Step 2.
Step 2: Directory interview
Walk the user through every path in config.directories. Present the default,
a one-sentence purpose, and allow inline editing. Paths are normalized
(strip trailing slash, resolve ~, keep as relative-to-workspace form that
starts with ./).
| Key | Default | Purpose |
|---|---|---|
resume_source |
./ResumeSourceFolder |
Master HAM-Z career data (user-maintained input) |
job_postings |
./Job_Postings |
Target job descriptions (user-maintained input) |
applications_root |
./Applications |
Per-application output tree (one folder per application) |
company_intelligence |
./Company_Intelligence |
OSINT output tree (shared across applications to same company) |
career_analysis |
./Career_Analysis |
Career-level outputs (idealjob, change-one-thing, comparejobs) |
crisis_management |
./Crisis_Management |
Crisis-skill outputs (severance, non-compete, etc.) |
tailored_cv |
./Tailored_CV |
Base resume library for revise-first /jobops:buildresume (one per role family) |
application_tracker |
./Applications/tracker.yaml |
Application status tracker maintained by /jobops:dashboard (one YAML file, not a folder) |
application_trackeris a file path, not a directory — Step 3 must notmkdirit. Its parent directory (applications_root) is already created, so no extra action is needed.
For each path: validate the parent is writable. If not, surface the specific error and allow the user to correct it before continuing.
Step 3: Create directories
For each confirmed path, run mkdir -p <path>. Report each as
created (newly made) or exists (already present). Do not fail if a
path already exists.
Skip
application_tracker— it is a file path, not a directory; its parent (applications_root) is already created by this loop.
Also mkdir -p .jobops .jobops/templates/default .jobops/templates/custom.
Step 4: Preferences interview
Ask in order:
- Cultural profile — enum
canadian|american. Defaultcanadian. Controls resume voice and spelling conventions. - Default jurisdiction — ISO 3166-2 code (e.g.,
CA-ON,US-CA). DefaultCA-ON. Used by crisis skills; they accept--jurisdiction=<code>to override per-invocation. - Cover letter mode — enum
retrospective|forward. Defaultretrospective. Controls how/jobops:coverletterwrites the letter.retrospectivemaps the job's requirements to what the candidate has already done.forwardproposes what the candidate would do in the first 90 days, tying each action to a real problem the role faces and to past work that proves the candidate can do it; it runs a short interview each time it is used. Override per-invocation with/jobops:coverletter --mode=retrospective|forward.
Do not ask for default_currency here — that is owned by /jobops-ic:setup
(see Step 4 of that flow).
Step 4b: Candidate contact details
Collect the contact fields that populate the resume and cover-letter headers. These
live in config.candidate so every document renders the same header and no field is
ever fused into another (the cover-letter header had no phone slot historically, which
produced fused (xxx) xxx-xxxxemail@example.com artifacts; the dedicated field fixes
this).
Ask for each (any may be left blank; blank fields are omitted from the header with their separator):
- Full name — e.g.,
Jane Doe - Credentials / post-nominals — e.g.,
CFA, FRICS(blank if none) - Location — e.g.,
Toronto, ON - Phone — e.g.,
(555) 555-1234(its own header field; never concatenated onto the email) - Email — e.g.,
jane.doe@example.com - LinkedIn — handle or URL, e.g.,
linkedin.com/in/janedoe - GitHub — handle or URL, e.g.,
github.com/janedoe(blank if none)
If the user prefers to keep contact details out of config, write the block with empty strings; the resume and cover-letter skills surface the gap rather than invent a value.
Step 5: Template installation
Copy the plugin's bundled templates into the workspace:
cp ${CLAUDE_PLUGIN_ROOT}/templates/*.md .jobops/templates/default/ 2>/dev/null || true
cp -r ${CLAUDE_PLUGIN_ROOT}/templates/latex .jobops/templates/default/
Report the count of files copied. Expected count after this task runs:
3 markdown templates (assessment_rubric_framework.md, evidence_verification_framework.md,
assessment_report_structure.md) plus 1 latex/ subdirectory (preamble.base.tex.template,
preamble.resume.tex.template, preamble.coverletter.tex.template,
preamble.document.tex.template, jobops-filter.lua, config.json, README.md).
If the glob fails in the current execution context (no files matched), fall back to:
find ${CLAUDE_PLUGIN_ROOT}/templates -maxdepth 1 -type f -exec cp {} .jobops/templates/default/ \;
cp -r ${CLAUDE_PLUGIN_ROOT}/templates/latex .jobops/templates/default/
Do not touch .jobops/templates/custom/ — it is user-owned.
Step 6: Write .jobops/config.json
Emit the full schema below with the values gathered in Steps 2 and 4.
migration.completed starts as false so Step 9 runs on first setup.
{
"version": "2.0",
"directories": {
"resume_source": "<step-2 value>",
"job_postings": "<step-2 value>",
"applications_root": "<step-2 value>",
"company_intelligence": "<step-2 value>",
"career_analysis": "<step-2 value>",
"crisis_management": "<step-2 value>",
"tailored_cv": "<step-2 value>",
"application_tracker": "<step-2 value>"
},
"preferences": {
"cultural_profile": "<step-4 value>",
"default_jurisdiction": "<step-4 value>",
"cover_letter_mode": "<step-4 value>"
},
"candidate": {
"name": "<step-4b value>",
"credentials": "<step-4b value>",
"location": "<step-4b value>",
"phone": "<step-4b value>",
"email": "<step-4b value>",
"linkedin": "<step-4b value>",
"github": "<step-4b value>"
},
"templates": {
"base_dir": "./.jobops/templates",
"active": {
"assessment_rubric_framework": "default",
"evidence_verification_framework": "default",
"assessment_report_structure": "default",
"latex_config": "default"
}
},
"migration": {
"completed": false,
"completed_at": null,
"files_moved": 0
}
}
Write atomically: write to .jobops/config.json.tmp, then mv over the final
name.
Step 7: Gitignore update
Show the user the JobOps block that will be appended to .gitignore:
# JobOps workspace
.jobops/
Applications/
Company_Intelligence/
Career_Analysis/
Crisis_Management/
(If the user customized any of the directory names in Step 2, substitute those paths in the block.)
Offer three choices:
- Append as shown — add the block to the end of
.gitignore. - Edit inline — let the user modify the block before appending.
- Skip — do not modify
.gitignore.
If .gitignore does not exist, create it. If the block (detected by the
# JobOps workspace marker line) already exists, replace it in place rather
than appending a second copy.
Step 8: Optional career-history import
Only offer this step if --skip-history was not passed and the
resume_source directory is empty or contains fewer than 3 files.
Prompt: "Do you have an existing resume to import as the basis for your HAM-Z career inventory? (yes/no)"
If yes, accept a path to a .pdf, .docx, .txt, or .md file. Extract
text, then populate:
{resume_source}/Experience/<Company>_<Role>.md— one file per role{resume_source}/CareerHighlights/highlights.md{resume_source}/Technology/stack.md{resume_source}/Preferences/preferences.md{resume_source}/Vision.md— stub, to be filled in manually
After population, flag any entries that lack metrics or hard skills so the user knows where to focus subsequent manual enrichment.
Step 9: Optional legacy migration
Skip this step if --skip-migration was passed OR migration.completed is
already true in the config being reconfigured.
Scan for legacy folders at the workspace root and subfolders named:
OutputResumes/Briefing_Notes/Scoring_Rubrics/Intelligence_Reports/
If all four are absent or empty, skip this step silently (and still set
migration.completed = true).
Otherwise run:
9a. Dry-run parse. For each file in the legacy folders, attempt to parse
{Company}_{Role}_{YYYYMMDD} from the filename using the following patterns
(tried in order):
^([A-Za-z0-9]+)_([A-Za-z0-9]+)_(\d{8})\.md$^(?:Step\d+_)?(?:Draft_|Provenance_Analysis_|Final_Resume_)?([A-Za-z0-9]+)_([A-Za-z0-9]+)_(\d{8})\.md$^Rubric_([A-Za-z0-9]+)_([A-Za-z0-9]+)_(\d{8})\.md$
For each match, compose a planned destination:
OutputResumes/Step1_*andStep2_*andStep3_*→{applications_root}/{Company}_{Role}_{Date}/resume/<stepN>.mdOutputResumes/Cover_Letter_*→{applications_root}/{Company}_{Role}_{Date}/cover-letter/cover_letter.mdScoring_Rubrics/Rubric_*→{applications_root}/{Company}_{Role}_{Date}/assessment/rubric.mdBriefing_Notes/*→{applications_root}/{Company}_{Role}_{Date}/interview/briefing.mdIntelligence_Reports/<Company>_*→{company_intelligence}/{Company}/<agent>.md(parse the agent name from the filename segment between Company and Date)
9b. Preview. Print the planned moves grouped by target app folder. List unresolved files (no regex match) in a separate "manual" group.
9c. User-editable mapping. Offer three options:
- Execute as shown — proceed with the preview.
- Edit mapping — drop into an inline editor where the user can reassign specific files to different application folders or mark them as "skip".
- Cancel — leave everything in place.
9d. Execute. For each confirmed move:
- If the file is tracked in git, use
git mv <src> <dst>(preserves history). - Otherwise use plain
mv. - Create any missing destination parent folders first.
9e. Update config. Set:
migration.completed = truemigration.completed_at = <ISO-8601 now>migration.files_moved = <count of successful moves>
Unresolved files stay in place; the user handles them manually.
Step 10: Summary and next steps
Print:
- What was configured (each path + confirm/created/exists).
- What was installed (template count).
- Whether career history was imported (and how many files).
- Whether migration ran (and how many files moved).
- Recommended next steps:
- Drop a job posting into
{job_postings}/named{Company}_{Role}_{YYYYMMDD}.md. - Run
/jobops:buildresume <job_posting.md>to produce a tailored resume. - Run
/jobops:osint <Company>to gather company intelligence. - If you are an independent contractor, run
/jobops-ic:setupto enable IC features.
- Drop a job posting into
Exit.