[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6KPV9Y54JZP1CMFCG0MAFHS":3,"skill-same:01M6KPV9Y54JZP1CMFCG0MAFHS":168},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":63,"commitSha":64,"skillDirectory":65,"forksCount":66,"repositoryHtmlUrl":67,"repositoryHomepageUrl":6,"ownerHtmlUrl":68,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":69,"install":70,"resources":83},"01M6KPV9Y54JZP1CMFCG0MAFHS","work-application",null,"CV generation, job scraping, offer analysis, and application tracking. Use when: (1) generating or adapting a CV\u002Fresume for a job offer, (2) scraping job offers from French platforms, (3) analyzing and ranking job offers, (4) generating a full analysis report for a single offer (skills, company, location, salary), (5) tracking candidatures and their status, (6) validating CV content against formatting guardrails. NOT for: cover letter generation (planned), LinkedIn direct messaging, job application submission, salary negotiation coaching.","bobvarkey\u002Fopenclaw-workspace","bobvarkey","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F72114170?v=4","01M6KP64KQA4GNH11CSV7FXKNB","Bob Varkey","01M6KP64R8P9B1QS9RRRX3N7EN",1,"MIT","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"work application","application","work","scraping","cover","ranking","french","market-data","files","master","reports","config","direct","analysis","Guardrails","data","network","analyzing","messaging","status","2026-11-10 10:12:30",false,"---\nname: work-application\ndescription: \"CV generation, job scraping, offer analysis, and application tracking. Use when: (1) generating or adapting a CV\u002Fresume for a job offer, (2) scraping job offers from French platforms, (3) analyzing and ranking job offers, (4) generating a full analysis report for a single offer (skills, company, location, salary), (5) tracking candidatures and their status, (6) validating CV content against formatting guardrails. NOT for: cover letter generation (planned), LinkedIn direct messaging, job application submission, salary negotiation coaching.\"\nhomepage: https:\u002F\u002Fgithub.com\u002Frwx-g\u002Fopenclaw-skill-work-application\ncompatibility: Python 3.9+ · Playwright (optional, for scraping) · No network required for CV generation\nmetadata:\n  {\n    \"openclaw\": {\n      \"emoji\": \"?\",\n      \"requires\": { \"env\": [] },\n      \"primaryEnv\": \"\",\n      \"suggests\": [\"nextcloud-files\"]\n    }\n  }\nontology:\n  reads: [profile-master, profile-adapted, candidatures, jobs, config, market-data]\n  writes: [profile-adapted, candidatures, jobs, cv-html, reports, market-data]\n  enhancedBy: [nextcloud-files]\n---\n\n# Work Application Skill\n\nJob search automation with CV generation, scraping, analysis, and tracking. 4 HTML CV templates (classic, modern-sidebar, two-column, creative), job scraping across 5 French platforms (Free-Work, WTTJ, Apec, HelloWork, LeHibou), keyword-based scoring, deep page analysis, full multi-dimension report (skills\u002Fcompany\u002Flocation\u002Fsalary with market data), and candidature tracking via markdown table. Stdlib only (except Playwright for scraping\u002Fanalysis). Supports local and Nextcloud storage.\n\nProfiles: `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F` · Config: `~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002Fconfig.json`\n\n## Trigger phrases\n\nLoad this skill when the user says anything like:\n- \"generate my CV\", \"create a resume\", \"render my CV\"\n- \"adapt my CV for this job offer\", \"tailor my resume\"\n- \"scrape job offers\", \"find jobs\", \"search for devops positions\"\n- \"analyze job offers\", \"rank these jobs\", \"score job matches\"\n- \"deep analyze these jobs\", \"scrape and analyze job pages\"\n- \"analyze this job offer\", \"generate a report for this URL\", \"report on this job\"\n- \"track this application\", \"log candidature\", \"update application status\"\n- \"list my applications\", \"show candidatures\"\n- \"validate my CV\", \"check CV formatting\"\n- \"show my profile\", \"what's in my master profile\"\n\n## Quick Start\n\n```bash\npython3 scripts\u002Fwork_application.py profile show\npython3 scripts\u002Fwork_application.py render --template classic --output cv.html\npython3 scripts\u002Fwork_application.py report \"https:\u002F\u002Fexample.com\u002Fjob-offer\"\npython3 scripts\u002Fwork_application.py track list\n```\n\n## Setup\n\n```bash\npython3 scripts\u002Fsetup.py       # interactive: profile + permissions + scraper config\npython3 scripts\u002Finit.py        # validate configuration\n```\n\n**config.json** - behavior restrictions (all destructive capabilities disabled by default):\n\n| Key | Default | Effect |\n|-----|---------|--------|\n| `allow_write` | **`false`** | allow modifying master profile |\n| `allow_export` | `true` | allow generating HTML\u002FPDF |\n| `allow_scrape` | **`false`** | allow running job scraper + network requests (requires Playwright) |\n| `allow_tracking` | `true` | allow logging candidatures |\n| `default_template` | `\"classic\"` | CV template when not specified |\n| `default_color` | `\"#2563eb\"` | accent color |\n| `default_lang` | `\"fr\"` | language (fr\u002Fen) |\n| `report_mode` | `\"analysis\"` | report output: `analysis` or `cv+analysis` |\n| `readonly_mode` | **`false`** | override: block **all** writes regardless of above |\n\n## Storage & data\n\n| Path | Written by | Purpose |\n|------|-----------|---------|\n| `~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002Fconfig.json` | `setup.py` | Permissions and defaults. No secrets. |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fprofile-master.json` | `setup.py` | Complete master profile (all experiences, skills, etc.) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fprofile.json` | Agent | Adapted profile for current job offer |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fcandidatures.md` | Agent | Application tracking table |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-found.md` | Scraper | Raw scraped job offers |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-ranked.md` | Analyzer | Scored and ranked offers |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-selected.md` | Analyzer | Top selection (CDI + Freelance) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fmarket-data.json` | Report | Market salary references (auto-generated, editable) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Freports\u002Freport-*.md` | Report | Full analysis reports (markdown) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Freports\u002Freport-*.json` | Report | Full analysis reports (JSON) |\n\n**Nextcloud storage** (optional): when `storage.backend = \"nextcloud\"` is set in config, files are stored on the user's Nextcloud instance instead of locally. Authentication is delegated entirely to the [`openclaw-skill-nextcloud`](https:\u002F\u002Fclawhub.ai\u002FRomain-Grosos\u002Fnextcloud-files) skill - this skill never handles Nextcloud credentials. The nextcloud skill must be installed separately.\n\n**Cleanup:** `python3 scripts\u002Fsetup.py --cleanup`\n\n**Uninstall:** `rm -rf ~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F ~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002F`\n\n## Security model\n\n### Capability isolation\n\nAll capabilities are disabled or restricted by default. The agent cannot perform actions until explicitly enabled in `config.json`:\n\n| Capability | Default | What it gates |\n|-----------|---------|---------------|\n| `allow_write` | `false` | Modify master profile |\n| `allow_export` | `true` | Generate HTML\u002FPDF output |\n| `allow_scrape` | `false` | Run Playwright browser, make network requests |\n| `allow_tracking` | `true` | Append to candidature log |\n| `readonly_mode` | `false` | Master kill-switch - blocks all writes |\n\n### Credential isolation\n\nThis skill stores **no secrets** and requires **no environment variables**. `config.json` contains only behavioral flags and defaults - never credentials.\n\n- **Local storage** (default): reads\u002Fwrites files under `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F`. No authentication needed.\n- **Nextcloud storage** (optional): delegates all authentication to the **[`openclaw-skill-nextcloud`](https:\u002F\u002Fclawhub.ai\u002FRomain-Grosos\u002Fnextcloud-files)** skill, which manages its own credentials (`NC_URL`, `NC_USER`, `NC_APP_KEY` in `~\u002F.openclaw\u002Fsecrets\u002Fnc_creds`). This skill never reads, stores, or handles Nextcloud credentials directly - it imports `NextcloudClient` from the nextcloud skill at runtime. The nextcloud skill must be installed and configured separately (`clawhub install nextcloud-files`).\n- **Scraping** (optional, `allow_scrape=true`): Playwright runs without authentication. Job pages are fetched as anonymous HTTP requests. Company review scraping (Glassdoor\u002FIndeed) also runs unauthenticated - no login or API key is used.\n\n### Path traversal protection\n\nAll storage operations (local and Nextcloud) validate filenames through `_validate_name()`:\n- Rejects absolute paths (`\u002Fetc\u002Fpasswd`, `C:\\...`)\n- Rejects traversal sequences (`..\u002F`, `..\\\\`, bare `..`)\n- Rejects null bytes (`\\x00`)\n- Normalizes slashes and collapses redundant separators\n- LocalStorage additionally resolves the final path and verifies it remains inside the storage root directory\n\n### HTML output safety\n\nAll profile fields are passed through `html.escape()` before HTML rendering. No raw user content is inserted into templates. This prevents XSS if the generated CV is served or shared.\n\n### Network boundaries\n\n- **No network calls** by default - CV generation, analysis, tracking are fully offline\n- Network calls only happen when `allow_scrape=true`, exclusively via Playwright (headless Chromium)\n- **Domains contacted when scraping**: `free-work.com`, `welcometothejungle.com`, `apec.fr`, `hellowork.com`, `lehibou.com` (job platforms), plus the specific job offer URL provided by the user\n- **Domains contacted by report** (optional, `allow_scrape=true`): `glassdoor.fr`, `fr.indeed.com` (company reviews - unauthenticated, anonymous)\n- **Nextcloud storage** (optional): contacts the user's own Nextcloud instance via the nextcloud skill - no third-party server\n- URLs built from user data (company names for review lookup) are properly URL-encoded\n- No background network activity, no telemetry, no phone-home\n\n### File output safety\n\n- Reports and CVs are written only to the configured storage directory (`~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F` or Nextcloud remote path)\n- Filenames derived from user data (company names) are strictly sanitized to ASCII alphanumeric + hyphens\n- Subdirectories (`reports\u002F`, `jobs\u002F`) are created inside the storage root only\n\n## Module usage\n\n```python\nfrom scripts._profile import load_master_profile, load_adapted_profile, save_adapted_profile\nfrom scripts._cv_renderer import render_cv\nfrom scripts._validators import validate_profile\nfrom scripts._tracker import log_application, list_applications, update_status\nfrom scripts._report import generate_report, format_report_markdown, save_report\n```\n\n## CLI reference\n\n```bash\n# Profile\npython3 scripts\u002Fwork_application.py profile show\npython3 scripts\u002Fwork_application.py profile validate\n\n# CV Rendering\npython3 scripts\u002Fwork_application.py render --template classic --output cv.html\npython3 scripts\u002Fwork_application.py render --template modern-sidebar --color \"#e63946\" --lang en\n\n# Job Scraping\npython3 scripts\u002Fwork_application.py scrape\npython3 scripts\u002Fwork_application.py scrape --platforms free-work,wttj\n\n# Job Analysis\npython3 scripts\u002Fwork_application.py analyze\n\n# Deep Analysis (scrape job pages for detailed matching)\npython3 scripts\u002Fwork_application.py deep-analyze\npython3 scripts\u002Fwork_application.py deep-analyze --max 10\n\n# Report (full multi-dimension analysis of a single offer)\npython3 scripts\u002Fwork_application.py report \"https:\u002F\u002Fexample.com\u002Fjob-offer\"\n\n# Application Tracking\npython3 scripts\u002Fwork_application.py track list\npython3 scripts\u002Fwork_application.py track list --status en_attente\npython3 scripts\u002Fwork_application.py track add \"Thales\" \"DevOps Engineer\" --location Paris --salary \"55-65k\"\npython3 scripts\u002Fwork_application.py track update \"Thales\" entretien\n\n# Config\npython3 scripts\u002Fwork_application.py config\n```\n\n## Templates\n\n### Adapt CV for a job offer\n```python\nfrom scripts._profile import load_master_profile, save_adapted_profile\nfrom scripts._cv_renderer import render_cv\nfrom scripts._validators import validate_profile\n\n# 1. Load master profile\nmaster = load_master_profile()\n# 2. Agent adapts profile for the job (select relevant skills, rewrite summary, etc.)\nadapted = adapt_for_job(master, job_description)  # agent logic\n# 3. Validate\nreport = validate_profile(adapted)\nif not report[\"valid\"]:\n    print(\"Errors:\", report[\"errors\"])\n# 4. Save and render\nsave_adapted_profile(adapted)\nhtml = render_cv(adapted, template=\"classic\", color=\"#2563eb\")\n```\n\n### Scrape → Analyze → Track\n```python\n# 1. Scrape jobs\nfrom scripts._scraper import JobScraper, filter_jobs, deduplicate\nscraper = JobScraper(config)\njobs = asyncio.run(scraper.scrape_all())\njobs = deduplicate(filter_jobs(jobs, config[\"scraper\"][\"filters\"]))\n\n# 2. Analyze\nfrom scripts._analyzer import rank_jobs, select_top\nranked = rank_jobs(jobs, master_profile)\nselected = select_top(ranked)\n\n# 3. Track top matches\nfrom scripts._tracker import log_application\nfor job in selected[\"cdi\"][:5]:\n    log_application(job[\"company\"], job[\"title\"], location=job.get(\"location\",\"\"))\n```\n\n### Quick candidature update\n```python\nfrom scripts._tracker import update_status, list_applications\nupdate_status(\"Thales\", \"entretien\")\nactive = list_applications(status=\"en_attente\")\n```\n\n## CV Templates\n\n| Template | Description | Best for |\n|----------|-------------|----------|\n| `classic` | Single-column, ATS-optimized | Most applications, ATS systems |\n| `modern-sidebar` | Sidebar (35%) + main (65%) | Tech companies, startups |\n| `two-column` | Two-column grid (38\u002F62) | Creative roles, design-aware |\n| `creative` | Timeline, gradient header | Personal branding, portfolios |\n\n## Status icons\n\n| Status | Icon | Meaning |\n|--------|------|---------|\n| `en_attente` | ⏳ | Waiting for response |\n| `entretien` | ? | Interview scheduled |\n| `negociation` | ? | In negotiation |\n| `offre` | ✅ | Offer received |\n| `refus` | ❌ | Rejected |\n| `desistement` | ? | Withdrawn |\n\n## Scraper platforms\n\n| Platform | URL | Types | Notes |\n|----------|-----|-------|-------|\n| Free-Work | free-work.com | Freelance | TJM parsing, remote detection |\n| WTTJ | welcometothejungle.com | CDI | Salary ranges, company pages |\n| Apec | apec.fr | CDI\u002FCadre | Executive positions |\n| HelloWork | hellowork.com | CDI | Broad coverage |\n| LeHibou | lehibou.com | Freelance | IT freelance missions |\n\n## Ideas\n- Set `allow_scrape: false` + `allow_export: true` for a CV-only mode\n- Use scraper with `allow_tracking: true` to auto-log the best matches\n- Adapt CV per job offer, validate, render, then log the application\n- Use `readonly_mode: true` for a safe demo mode\n\n## Notes\n- **Playwright dependency**: Only needed for scraping. CV generation is stdlib only.\n- **Profile structure**: Master profile contains ALL data. Adapted profile is a filtered subset for a specific job.\n- **Validators**: Port of the JavaScript validators - same limits and thresholds.\n- **i18n**: CV rendering supports French and English section headings.\n- **Print-ready**: Generated HTML includes @media print rules and A4 page breaks.\n\n## Combine with\n\n| Skill | Workflow |\n|-------|----------|\n| **ghost** | Generate CV → publish as Ghost page |\n| **nextcloud** | Save rendered CV to Nextcloud |\n| **gmail** | Send CV as email attachment |\n| **veille** | Monitor job market trends → adapt search queries |\n\n## API reference\nSee `references\u002Fapi.md` for CLI command details and profile schema.\n\n## Troubleshooting\nSee `references\u002Ftroubleshooting.md` for common errors and fixes.\n","# Work Application Skill\n\nJob search automation with CV generation, scraping, analysis, and tracking. 4 HTML CV templates (classic, modern-sidebar, two-column, creative), job scraping across 5 French platforms (Free-Work, WTTJ, Apec, HelloWork, LeHibou), keyword-based scoring, deep page analysis, full multi-dimension report (skills\u002Fcompany\u002Flocation\u002Fsalary with market data), and candidature tracking via markdown table. Stdlib only (except Playwright for scraping\u002Fanalysis). Supports local and Nextcloud storage.\n\nProfiles: `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F` · Config: `~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002Fconfig.json`\n\n## Trigger phrases\n\nLoad this skill when the user says anything like:\n- \"generate my CV\", \"create a resume\", \"render my CV\"\n- \"adapt my CV for this job offer\", \"tailor my resume\"\n- \"scrape job offers\", \"find jobs\", \"search for devops positions\"\n- \"analyze job offers\", \"rank these jobs\", \"score job matches\"\n- \"deep analyze these jobs\", \"scrape and analyze job pages\"\n- \"analyze this job offer\", \"generate a report for this URL\", \"report on this job\"\n- \"track this application\", \"log candidature\", \"update application status\"\n- \"list my applications\", \"show candidatures\"\n- \"validate my CV\", \"check CV formatting\"\n- \"show my profile\", \"what's in my master profile\"\n\n## Quick Start\n\n```bash\npython3 scripts\u002Fwork_application.py profile show\npython3 scripts\u002Fwork_application.py render --template classic --output cv.html\npython3 scripts\u002Fwork_application.py report \"https:\u002F\u002Fexample.com\u002Fjob-offer\"\npython3 scripts\u002Fwork_application.py track list\n```\n\n## Setup\n\n```bash\npython3 scripts\u002Fsetup.py       # interactive: profile + permissions + scraper config\npython3 scripts\u002Finit.py        # validate configuration\n```\n\n**config.json** - behavior restrictions (all destructive capabilities disabled by default):\n\n| Key | Default | Effect |\n|-----|---------|--------|\n| `allow_write` | **`false`** | allow modifying master profile |\n| `allow_export` | `true` | allow generating HTML\u002FPDF |\n| `allow_scrape` | **`false`** | allow running job scraper + network requests (requires Playwright) |\n| `allow_tracking` | `true` | allow logging candidatures |\n| `default_template` | `\"classic\"` | CV template when not specified |\n| `default_color` | `\"#2563eb\"` | accent color |\n| `default_lang` | `\"fr\"` | language (fr\u002Fen) |\n| `report_mode` | `\"analysis\"` | report output: `analysis` or `cv+analysis` |\n| `readonly_mode` | **`false`** | override: block **all** writes regardless of above |\n\n## Storage & data\n\n| Path | Written by | Purpose |\n|------|-----------|---------|\n| `~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002Fconfig.json` | `setup.py` | Permissions and defaults. No secrets. |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fprofile-master.json` | `setup.py` | Complete master profile (all experiences, skills, etc.) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fprofile.json` | Agent | Adapted profile for current job offer |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fcandidatures.md` | Agent | Application tracking table |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-found.md` | Scraper | Raw scraped job offers |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-ranked.md` | Analyzer | Scored and ranked offers |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fjobs\u002Fjobs-selected.md` | Analyzer | Top selection (CDI + Freelance) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Fmarket-data.json` | Report | Market salary references (auto-generated, editable) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Freports\u002Freport-*.md` | Report | Full analysis reports (markdown) |\n| `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002Freports\u002Freport-*.json` | Report | Full analysis reports (JSON) |\n\n**Nextcloud storage** (optional): when `storage.backend = \"nextcloud\"` is set in config, files are stored on the user's Nextcloud instance instead of locally. Authentication is delegated entirely to the [`openclaw-skill-nextcloud`](https:\u002F\u002Fclawhub.ai\u002FRomain-Grosos\u002Fnextcloud-files) skill - this skill never handles Nextcloud credentials. The nextcloud skill must be installed separately.\n\n**Cleanup:** `python3 scripts\u002Fsetup.py --cleanup`\n\n**Uninstall:** `rm -rf ~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F ~\u002F.openclaw\u002Fconfig\u002Fwork-application\u002F`\n\n## Security model\n\n### Capability isolation\n\nAll capabilities are disabled or restricted by default. The agent cannot perform actions until explicitly enabled in `config.json`:\n\n| Capability | Default | What it gates |\n|-----------|---------|---------------|\n| `allow_write` | `false` | Modify master profile |\n| `allow_export` | `true` | Generate HTML\u002FPDF output |\n| `allow_scrape` | `false` | Run Playwright browser, make network requests |\n| `allow_tracking` | `true` | Append to candidature log |\n| `readonly_mode` | `false` | Master kill-switch - blocks all writes |\n\n### Credential isolation\n\nThis skill stores **no secrets** and requires **no environment variables**. `config.json` contains only behavioral flags and defaults - never credentials.\n\n- **Local storage** (default): reads\u002Fwrites files under `~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F`. No authentication needed.\n- **Nextcloud storage** (optional): delegates all authentication to the **[`openclaw-skill-nextcloud`](https:\u002F\u002Fclawhub.ai\u002FRomain-Grosos\u002Fnextcloud-files)** skill, which manages its own credentials (`NC_URL`, `NC_USER`, `NC_APP_KEY` in `~\u002F.openclaw\u002Fsecrets\u002Fnc_creds`). This skill never reads, stores, or handles Nextcloud credentials directly - it imports `NextcloudClient` from the nextcloud skill at runtime. The nextcloud skill must be installed and configured separately (`clawhub install nextcloud-files`).\n- **Scraping** (optional, `allow_scrape=true`): Playwright runs without authentication. Job pages are fetched as anonymous HTTP requests. Company review scraping (Glassdoor\u002FIndeed) also runs unauthenticated - no login or API key is used.\n\n### Path traversal protection\n\nAll storage operations (local and Nextcloud) validate filenames through `_validate_name()`:\n- Rejects absolute paths (`\u002Fetc\u002Fpasswd`, `C:\\...`)\n- Rejects traversal sequences (`..\u002F`, `..\\\\`, bare `..`)\n- Rejects null bytes (`\\x00`)\n- Normalizes slashes and collapses redundant separators\n- LocalStorage additionally resolves the final path and verifies it remains inside the storage root directory\n\n### HTML output safety\n\nAll profile fields are passed through `html.escape()` before HTML rendering. No raw user content is inserted into templates. This prevents XSS if the generated CV is served or shared.\n\n### Network boundaries\n\n- **No network calls** by default - CV generation, analysis, tracking are fully offline\n- Network calls only happen when `allow_scrape=true`, exclusively via Playwright (headless Chromium)\n- **Domains contacted when scraping**: `free-work.com`, `welcometothejungle.com`, `apec.fr`, `hellowork.com`, `lehibou.com` (job platforms), plus the specific job offer URL provided by the user\n- **Domains contacted by report** (optional, `allow_scrape=true`): `glassdoor.fr`, `fr.indeed.com` (company reviews - unauthenticated, anonymous)\n- **Nextcloud storage** (optional): contacts the user's own Nextcloud instance via the nextcloud skill - no third-party server\n- URLs built from user data (company names for review lookup) are properly URL-encoded\n- No background network activity, no telemetry, no phone-home\n\n### File output safety\n\n- Reports and CVs are written only to the configured storage directory (`~\u002F.openclaw\u002Fdata\u002Fwork-application\u002F` or Nextcloud remote path)\n- Filenames derived from user data (company names) are strictly sanitized to ASCII alphanumeric + hyphens\n- Subdirectories (`reports\u002F`, `jobs\u002F`) are created inside the storage root only\n\n## Module usage\n\n```python\nfrom scripts._profile import load_master_profile, load_adapted_profile, save_adapted_profile\nfrom scripts._cv_renderer import render_cv\nfrom scripts._validators import validate_profile\nfrom scripts._tracker import log_application, list_applications, update_status\nfrom scripts._report import generate_report, format_report_markdown, save_report\n```\n\n## CLI reference\n\n```bash\n# Profile\npython3 scripts\u002Fwork_application.py profile show\npython3 scripts\u002Fwork_application.py profile validate\n\n# CV Rendering\npython3 scripts\u002Fwork_application.py render --template classic --output cv.html\npython3 scripts\u002Fwork_application.py render --template modern-sidebar --color \"#e63946\" --lang en\n\n# Job Scraping\npython3 scripts\u002Fwork_application.py scrape\npython3 scripts\u002Fwork_application.py scrape --platforms free-work,wttj\n\n# Job Analysis\npython3 scripts\u002Fwork_application.py analyze\n\n# Deep Analysis (scrape job pages for detailed matching)\npython3 scripts\u002Fwork_application.py deep-analyze\npython3 scripts\u002Fwork_application.py deep-analyze --max 10\n\n# Report (full multi-dimension analysis of a single offer)\npython3 scripts\u002Fwork_application.py report \"https:\u002F\u002Fexample.com\u002Fjob-offer\"\n\n# Application Tracking\npython3 scripts\u002Fwork_application.py track list\npython3 scripts\u002Fwork_application.py track list --status en_attente\npython3 scripts\u002Fwork_application.py track add \"Thales\" \"DevOps Engineer\" --location Paris --salary \"55-65k\"\npython3 scripts\u002Fwork_application.py track update \"Thales\" entretien\n\n# Config\npython3 scripts\u002Fwork_application.py config\n```\n\n## Templates\n\n### Adapt CV for a job offer\n```python\nfrom scripts._profile import load_master_profile, save_adapted_profile\nfrom scripts._cv_renderer import render_cv\nfrom scripts._validators import validate_profile\n\n# 1. Load master profile\nmaster = load_master_profile()\n# 2. Agent adapts profile for the job (select relevant skills, rewrite summary, etc.)\nadapted = adapt_for_job(master, job_description)  # agent logic\n# 3. Validate\nreport = validate_profile(adapted)\nif not report[\"valid\"]:\n    print(\"Errors:\", report[\"errors\"])\n# 4. Save and render\nsave_adapted_profile(adapted)\nhtml = render_cv(adapted, template=\"classic\", color=\"#2563eb\")\n```\n\n### Scrape → Analyze → Track\n```python\n# 1. Scrape jobs\nfrom scripts._scraper import JobScraper, filter_jobs, deduplicate\nscraper = JobScraper(config)\njobs = asyncio.run(scraper.scrape_all())\njobs = deduplicate(filter_jobs(jobs, config[\"scraper\"][\"filters\"]))\n\n# 2. Analyze\nfrom scripts._analyzer import rank_jobs, select_top\nranked = rank_jobs(jobs, master_profile)\nselected = select_top(ranked)\n\n# 3. Track top matches\nfrom scripts._tracker import log_application\nfor job in selected[\"cdi\"][:5]:\n    log_application(job[\"company\"], job[\"title\"], location=job.get(\"location\",\"\"))\n```\n\n### Quick candidature update\n```python\nfrom scripts._tracker import update_status, list_applications\nupdate_status(\"Thales\", \"entretien\")\nactive = list_applications(status=\"en_attente\")\n```\n\n## CV Templates\n\n| Template | Description | Best for |\n|----------|-------------|----------|\n| `classic` | Single-column, ATS-optimized | Most applications, ATS systems |\n| `modern-sidebar` | Sidebar (35%) + main (65%) | Tech companies, startups |\n| `two-column` | Two-column grid (38\u002F62) | Creative roles, design-aware |\n| `creative` | Timeline, gradient header | Personal branding, portfolios |\n\n## Status icons\n\n| Status | Icon | Meaning |\n|--------|------|---------|\n| `en_attente` | ⏳ | Waiting for response |\n| `entretien` | ? | Interview scheduled |\n| `negociation` | ? | In negotiation |\n| `offre` | ✅ | Offer received |\n| `refus` | ❌ | Rejected |\n| `desistement` | ? | Withdrawn |\n\n## Scraper platforms\n\n| Platform | URL | Types | Notes |\n|----------|-----|-------|-------|\n| Free-Work | free-work.com | Freelance | TJM parsing, remote detection |\n| WTTJ | welcometothejungle.com | CDI | Salary ranges, company pages |\n| Apec | apec.fr | CDI\u002FCadre | Executive positions |\n| HelloWork | hellowork.com | CDI | Broad coverage |\n| LeHibou | lehibou.com | Freelance | IT freelance missions |\n\n## Ideas\n- Set `allow_scrape: false` + `allow_export: true` for a CV-only mode\n- Use scraper with `allow_tracking: true` to auto-log the best matches\n- Adapt CV per job offer, validate, render, then log the application\n- Use `readonly_mode: true` for a safe demo mode\n\n## Notes\n- **Playwright dependency**: Only needed for scraping. CV generation is stdlib only.\n- **Profile structure**: Master profile contains ALL data. Adapted profile is a filtered subset for a specific job.\n- **Validators**: Port of the JavaScript validators - same limits and thresholds.\n- **i18n**: CV rendering supports French and English section headings.\n- **Print-ready**: Generated HTML includes @media print rules and A4 page breaks.\n\n## Combine with\n\n| Skill | Workflow |\n|-------|----------|\n| **ghost** | Generate CV → publish as Ghost page |\n| **nextcloud** | Save rendered CV to Nextcloud |\n| **gmail** | Send CV as email attachment |\n| **veille** | Monitor job market trends → adapt search queries |\n\n## API reference\nSee `references\u002Fapi.md` for CLI command details and profile schema.\n\n## Troubleshooting\nSee `references\u002Ftroubleshooting.md` for common errors and fixes.\n",{"name":5,"homepage":44,"metadata":45,"ontology":53,"description":7,"compatibility":62},"https:\u002F\u002Fgithub.com\u002Frwx-g\u002Fopenclaw-skill-work-application",{"openclaw":46},{"emoji":47,"requires":48,"suggests":50,"primaryEnv":52},"?",{"env":49},[],[51],"nextcloud-files","",{"reads":54,"writes":59,"enhancedBy":61},[55,56,57,58,30,26],"profile-master","profile-adapted","candidatures","jobs",[56,57,58,60,29,26],"cv-html",[51],"Python 3.9+ · Playwright (optional, for scraping) · No network required for CV generation","main","d8f4d173ae7b04884241c26e6bea57eb3f1888da","skills\u002Fwork-application",0,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace","https:\u002F\u002Fgithub.com\u002Fbobvarkey","2026-06-16 18:18:27",{"source":8,"skillName":5,"commands":71,"prompt":81,"zipAvailable":82},[72,75,78],{"tool":73,"command":74},"npx","npx skills add bobvarkey\u002Fopenclaw-workspace --skill work-application",{"tool":76,"command":77},"bunx","bunx skills add bobvarkey\u002Fopenclaw-workspace --skill work-application",{"tool":79,"command":80},"pnpm","pnpm dlx skills add bobvarkey\u002Fopenclaw-workspace --skill work-application","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002FSKILL.md",true,[84,90,94,98,102,106,110,116,120,124,128,132,136,140,144,148,152,156,160,164],{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"_meta.json","REFERENCE","参考文档",136,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002F_meta.json",{"path":91,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":92,"sourceHtmlUrl":93},".clawhub\u002Forigin.json",149,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002F.clawhub\u002Forigin.json",{"path":95,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":96,"sourceHtmlUrl":97},"config.example.json",984,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fconfig.example.json",{"path":99,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":100,"sourceHtmlUrl":101},"README.md",6810,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002FREADME.md",{"path":103,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":104,"sourceHtmlUrl":105},"references\u002Fapi.md",5715,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Freferences\u002Fapi.md",{"path":107,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":108,"sourceHtmlUrl":109},"references\u002Ftroubleshooting.md",5275,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Freferences\u002Ftroubleshooting.md",{"path":111,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":114,"sourceHtmlUrl":115},"scripts\u002F_analyzer.py","SCRIPT","脚本",42906,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_analyzer.py",{"path":117,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":118,"sourceHtmlUrl":119},"scripts\u002F_cv_renderer.py",36449,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_cv_renderer.py",{"path":121,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":122,"sourceHtmlUrl":123},"scripts\u002F_cv_styles.py",32304,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_cv_styles.py",{"path":125,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":126,"sourceHtmlUrl":127},"scripts\u002F_pdf_exporter.py",2049,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_pdf_exporter.py",{"path":129,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":130,"sourceHtmlUrl":131},"scripts\u002F_profile.py",6928,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_profile.py",{"path":133,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":134,"sourceHtmlUrl":135},"scripts\u002F_report.py",45332,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_report.py",{"path":137,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":138,"sourceHtmlUrl":139},"scripts\u002F_retry.py",1508,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_retry.py",{"path":141,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":142,"sourceHtmlUrl":143},"scripts\u002F_scraper.py",36328,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_scraper.py",{"path":145,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":146,"sourceHtmlUrl":147},"scripts\u002F_storage.py",8218,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_storage.py",{"path":149,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":150,"sourceHtmlUrl":151},"scripts\u002F_tracker.py",6894,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_tracker.py",{"path":153,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":154,"sourceHtmlUrl":155},"scripts\u002F_validators.py",9521,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002F_validators.py",{"path":157,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":158,"sourceHtmlUrl":159},"scripts\u002Finit.py",9697,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002Finit.py",{"path":161,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":162,"sourceHtmlUrl":163},"scripts\u002Fsetup.py",38479,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002Fsetup.py",{"path":165,"resourceType":112,"resourceTypeDesc":113,"sizeBytes":166,"sourceHtmlUrl":167},"scripts\u002Fwork_application.py",22612,"https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fwork-application\u002Fscripts\u002Fwork_application.py",[169,203,234,245,271,289],{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":185,"publishedAt":39},"01M6KPWMVDQ1BSMVR82HXAX8AC","youtube","YouTube Data API integration with managed OAuth. Search videos, manage playlists, access channel data, and interact with comments. Use this skill when users want to interact with YouTube. For other third party apps, use the api-gateway skill (https:\u002F\u002Fclawhub.ai\u002Fbyungkyu\u002Fapi-gateway).","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-api-skill\u002FSKILL.md",[175,180],{"categoryNo":176,"categoryName":177,"taxonomyType":178,"taxonomyTypeDesc":179},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":181,"categoryName":182,"taxonomyType":183,"taxonomyTypeDesc":184},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[171,186,187,188,189,190,191,192,193,194,195,196,197,198,34,35,199,200,201,202],"for","managed","OAuth","maton","api integration","manage","apps","use","access","api","comments","api-gateway","gateway skill","gateway","search","valid","clawhub",{"skillNo":204,"name":205,"nameZh":6,"description":206,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":207,"categories":208,"keywords":215,"publishedAt":39},"01M6KPVYGSVBMFX5JP52JW8V97","xcellent","Free, open-source X (Twitter) growth tool. Analytics dashboard, niche discovery, AI tweet writer, best posting times, and credit usage monitoring — all running locally on your machine. BYOK (Bring Your Own Key) model means users only pay X directly for API usage (~$5-15\u002Fmo). A free alternative to SuperX ($39\u002Fmo), Typefully, and Tweet Hunter.","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fxcellent\u002FSKILL.md",[209,212],{"categoryNo":210,"categoryName":211,"taxonomyType":178,"taxonomyTypeDesc":179},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":213,"categoryName":214,"taxonomyType":183,"taxonomyTypeDesc":184},"01JBSEEDCAT000000000000033","数据分析师",[205,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,186,232,233],"growth","machine","hunter","free","posting","writer","typefully","tweet writer","only","pay","twitter","model","tool","open","discovery","analytics dashboard","bring","usage",{"skillNo":235,"name":236,"nameZh":6,"description":237,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":238,"categories":239,"keywords":240,"publishedAt":39},"01M6KPTNDAC8V0AHK2ZF3ANY3B","weather","Get current weather and forecasts (no API key required).","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fweather\u002FSKILL.md",[],[236,241,242,243,244,195],"get","curl","https","help",{"skillNo":246,"name":247,"nameZh":6,"description":248,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":249,"categories":250,"keywords":251,"publishedAt":39},"01M6KPT3JVWXD5T5P99D7S9KPE","to-do","Give your AI the power to act in the future. Schedule delayed prompts and one-off reminders that automatically wake the agent up at an exact moment to execute workflows, check systems, or send notifications.","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fto-do\u002FSKILL.md",[],[252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270],"to do","do","power","send","tz","wake","at","systems","act","prompts","up","execute","check","node","schedule","notifications","reminders","workflows","openclaw",{"skillNo":272,"name":273,"nameZh":6,"description":274,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":275,"categories":276,"keywords":280,"publishedAt":39},"01M6KPSRT9BCV73F9EAAP66QAF","summarize","Summarize URLs or files with the summarize CLI (web, PDFs, images, audio, YouTube).","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fsummarize\u002FSKILL.md",[277],{"categoryNo":278,"categoryName":279,"taxonomyType":178,"taxonomyTypeDesc":179},"01JBSEEDCAT000000000000021","资料检索与研究",[273,171,27,281,282,283,284,243,285,286,287,288],"images","install","brew","Audio","web","cli","tap","with",{"skillNo":290,"name":291,"nameZh":6,"description":292,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":293,"categories":294,"keywords":295,"publishedAt":39},"01M6KPSDA8RF6V5Z4R4M0P1SDH","security-audit","Comprehensive security auditing for Clawdbot deployments. Scans for exposed credentials, open ports, weak configs, and vulnerabilities. Auto-fix mode included.","https:\u002F\u002Fgithub.com\u002Fbobvarkey\u002Fopenclaw-workspace\u002Fblob\u002Fmain\u002Fskills\u002Fsecurity-audit\u002FSKILL.md",[],[296,297,298,299,186,300,301,302,303,304,305,229,306,307],"security","audit","security audit","mode","security auditing","clawdbot","deployments","auto","fix","ports","credentials","vulnerabilities"]