Files
claw-apply/SPEC.md

6.8 KiB

claw-apply — Skill Spec v0.1

Automated job search and application skill for OpenClaw. Searches LinkedIn and Wellfound for matching roles, applies automatically using Playwright + Kernel stealth browsers.


Architecture

Two agents

JobSearcher (job_searcher.mjs)

  • Runs on a schedule (default: hourly)
  • Searches configured platforms with configured queries
  • Filters out excluded roles/companies
  • Dedupes against existing queue
  • Writes new jobs to jobs_queue.json with status new
  • Sends Telegram summary: "Found X new jobs"

JobApplier (job_applier.mjs)

  • Runs on a schedule (default: every 6 hours)
  • Reads jobs_queue.json for status new + needs_answer
  • Attempts to apply to each job
  • On success → status: applied
  • On unknown question → messages user via Telegram, status: needs_answer
  • On skip/fail → status: skipped or failed
  • Sends Telegram summary when done

Config Files (user sets up once)

profile.json

{
  "name": { "first": "Jane", "last": "Smith" },
  "email": "jane@example.com",
  "phone": "555-123-4567",
  "location": {
    "city": "San Francisco",
    "state": "California",
    "zip": "94102",
    "country": "United States"
  },
  "linkedin_url": "https://linkedin.com/in/janesmith",
  "resume_path": "/home/user/resume.pdf",
  "years_experience": 7,
  "work_authorization": {
    "authorized": true,
    "requires_sponsorship": false
  },
  "willing_to_relocate": false,
  "desired_salary": 150000,
  "cover_letter": "Your cover letter text here..."
}

search_config.json

{
  "searches": [
    {
      "name": "Founding GTM",
      "track": "gtm",
      "keywords": [
        "founding account executive",
        "first sales hire",
        "first GTM hire",
        "founding AE",
        "head of sales startup remote"
      ],
      "platforms": ["linkedin", "wellfound"],
      "filters": {
        "remote": true,
        "posted_within_days": 2
      },
      "exclude_keywords": ["BDR", "SDR", "staffing", "insurance", "retail", "consumer", "recruiter"],
      "salary_min": 130000
    },
    {
      "name": "Enterprise AE",
      "track": "ae",
      "keywords": [
        "enterprise account executive SaaS remote",
        "senior account executive technical SaaS remote"
      ],
      "platforms": ["linkedin"],
      "filters": {
        "remote": true,
        "posted_within_days": 2,
        "easy_apply_only": true
      },
      "exclude_keywords": ["BDR", "SDR", "SMB", "staffing"],
      "salary_min": 150000
    }
  ]
}

answers.json

Flat array of pattern → answer mappings. Pattern is substring match (case-insensitive). First match wins.

[
  { "pattern": "quota attainment", "answer": "1.12", "note": "FY24 $1.2M quota, hit $1.12M" },
  { "pattern": "sponsor", "answer": "No" },
  { "pattern": "authorized", "answer": "Yes" },
  { "pattern": "relocat", "answer": "No" },
  { "pattern": "years.*sales", "answer": "7" },
  { "pattern": "years.*enterprise", "answer": "5" },
  { "pattern": "years.*crm", "answer": "7" },
  { "pattern": "1.*10.*scale", "answer": "9" },
  { "pattern": "salary", "answer": "150000" },
  { "pattern": "start date", "answer": "Immediately" }
]

settings.json

{
  "mode": "A",
  "review_window_minutes": 30,
  "schedules": {
    "search": "0 * * * *",
    "apply": "0 */6 * * *"
  },
  "max_applications_per_run": 50,
  "notifications": {
    "telegram_user_id": "YOUR_TELEGRAM_ID"
  },
  "kernel": {
    "proxy_id": "YOUR_KERNEL_PROXY_ID",
    "profiles": {
      "linkedin": "LinkedIn-YourName",
      "wellfound": "WellFound-YourName"
    }
  },
  "browser": {
    "provider": "kernel",
    "fallback": "local"
  }
}

Data Files (auto-managed)

jobs_queue.json

[
  {
    "id": "li_4381658809",
    "platform": "linkedin",
    "track": "ae",
    "title": "Senior Account Executive",
    "company": "Acme Corp",
    "url": "https://linkedin.com/jobs/view/4381658809/",
    "found_at": "2026-03-05T22:00:00Z",
    "status": "new",
    "status_updated_at": "2026-03-05T22:00:00Z",
    "pending_question": null,
    "applied_at": null,
    "notes": null
  }
]

Statuses: newapplied / skipped / failed / needs_answer

applications_log.json

Append-only history of every application attempt with outcome.


Unknown Question Flow

  1. Applier hits a required field it can't answer
  2. Marks job as needs_answer, stores the question text in pending_question
  3. Sends Telegram: "Applying to Senior AE @ Acme Corp and hit this question: 'What was your last quota attainment in $M?' — what should I answer?"
  4. Moves on to next job
  5. User replies → answer saved to answers.json
  6. Next applier run retries all needs_answer jobs

Mode A vs Mode B

Mode A (fully automatic): Search → Queue → Apply. No intervention required.

Mode B (soft gate): Search → Queue → Telegram summary sent to user → 30 min window to reply with any job IDs to skip → Apply runs.

Configured via settings.jsonmode: "A" or "B"


File Structure

claw-apply/
├── SKILL.md              ← OpenClaw skill entry point
├── SPEC.md               ← this file
├── job_searcher.mjs      ← search agent
├── job_applier.mjs       ← apply agent
├── lib/
│   ├── browser.mjs       ← Kernel/Playwright browser factory
│   ├── form_filler.mjs   ← form filling logic
│   ├── linkedin.mjs      ← LinkedIn search + apply
│   ├── wellfound.mjs     ← Wellfound search + apply
│   └── notify.mjs        ← Telegram notifications
├── config/
│   ├── profile.json      ← user fills this
│   ├── search_config.json← user fills this
│   ├── answers.json      ← auto-grows over time
│   └── settings.json     ← user fills this
└── data/
    ├── jobs_queue.json   ← auto-managed
    └── applications_log.json ← auto-managed

Setup (user steps)

  1. Install: openclaw skill install claw-apply
  2. Configure Kernel Managed Auth for LinkedIn + Wellfound (or provide local Chrome)
  3. Create a residential proxy in Kernel: kernel proxies create --type residential --country US
  4. Fill in config/profile.json, config/search_config.json, config/settings.json
  5. Run: openclaw skill run claw-apply setup — registers crons, verifies login, sends test notification
  6. Done. Runs automatically.

v1 Scope

  • LinkedIn Easy Apply
  • Wellfound apply
  • Kernel stealth browser + residential proxy
  • Mode A + Mode B
  • Unknown question → Telegram → answers.json flow
  • Deduplication
  • Hourly search / 6hr apply cron
  • Indeed (v2)
  • External ATS / Greenhouse / Lever (v2)
  • Job scoring/ranking (v2)
  • Cover letter generation per-job via LLM (v2)