docs: add README, update SKILL.md and SPEC.md for current state
- Full README with quick start, configuration tables, status reference, project structure, and roadmap - SKILL.md updated with preview mode, retry logic, constants module - SPEC.md updated with pagination, infinite scroll, retry flow, in-memory caching, config validation, and v1 checklist Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
109
SKILL.md
109
SKILL.md
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: claw-apply
|
||||
description: Automated job search and application for LinkedIn and Wellfound. Searches for matching roles hourly, applies automatically every 6 hours using Playwright + Kernel stealth browsers. Handles LinkedIn Easy Apply and Wellfound applications. Asks you via Telegram when it hits a question it can't answer, saves your answer, and never asks again. Use when you want to automate your job search and application process.
|
||||
description: Automated job search and application for LinkedIn and Wellfound. Searches for matching roles hourly, applies automatically every 6 hours using Playwright + Kernel stealth browsers. Handles LinkedIn Easy Apply multi-step modals and Wellfound applications. Self-learning — asks you via Telegram when it hits an unknown question, saves your answer, and never asks again. Retries failed applications automatically. Preview mode lets you review the queue before applying.
|
||||
---
|
||||
|
||||
# claw-apply
|
||||
@@ -9,7 +9,8 @@ Automated job search and application. Finds matching roles on LinkedIn and Wellf
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Kernel.sh](https://kernel.sh) account (for stealth browsers + bot detection bypass)
|
||||
- Node.js 18+
|
||||
- [Kernel](https://kernel.sh) account (stealth browsers + bot detection bypass) — or local Playwright
|
||||
- Kernel CLI: `npm install -g @onkernel/cli`
|
||||
- Kernel Managed Auth sessions for LinkedIn and Wellfound
|
||||
- Kernel residential proxy (US recommended)
|
||||
@@ -17,97 +18,95 @@ Automated job search and application. Finds matching roles on LinkedIn and Wellf
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install dependencies
|
||||
### 1. Install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/MattJackson/claw-apply.git
|
||||
cd claw-apply
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Create Kernel Managed Auth sessions
|
||||
### 2. Create Kernel browser sessions
|
||||
|
||||
```bash
|
||||
# Create residential proxy
|
||||
kernel proxies create --type residential --country US --name "claw-apply-proxy"
|
||||
|
||||
# Create authenticated browser profiles
|
||||
kernel auth create --name "LinkedIn-YourName" # Follow prompts to log in
|
||||
kernel auth create --name "WellFound-YourName" # Follow prompts to log in
|
||||
kernel auth create --name "LinkedIn-YourName"
|
||||
kernel auth create --name "WellFound-YourName"
|
||||
```
|
||||
|
||||
### 3. Configure
|
||||
Edit these files in `config/`:
|
||||
|
||||
- **`profile.json`** — your personal info, resume path, cover letter
|
||||
- **`search_config.json`** — what jobs to search for (titles, keywords, filters)
|
||||
- **`settings.json`** — Telegram bot token, Kernel profile names, proxy ID, mode A/B
|
||||
Copy example configs and fill in your values:
|
||||
|
||||
```bash
|
||||
cp config/settings.example.json config/settings.json
|
||||
cp config/profile.example.json config/profile.json
|
||||
cp config/search_config.example.json config/search_config.json
|
||||
```
|
||||
|
||||
- **`profile.json`** — name, email, phone, resume path, work authorization, salary
|
||||
- **`search_config.json`** — keywords, platforms, filters, exclusions
|
||||
- **`settings.json`** — Telegram bot token, Kernel profile names, proxy ID, run caps
|
||||
|
||||
### 4. Verify
|
||||
|
||||
### 4. Run setup
|
||||
```bash
|
||||
KERNEL_API_KEY=your_key node setup.mjs
|
||||
```
|
||||
|
||||
Verifies config, tests logins, sends a test Telegram message.
|
||||
### 5. Run
|
||||
|
||||
```bash
|
||||
KERNEL_API_KEY=your_key node job_searcher.mjs # search now
|
||||
KERNEL_API_KEY=your_key node job_applier.mjs --preview # preview queue
|
||||
KERNEL_API_KEY=your_key node job_applier.mjs # apply now
|
||||
```
|
||||
|
||||
### 6. Schedule (via OpenClaw or cron)
|
||||
|
||||
### 5. Register cron jobs (via OpenClaw)
|
||||
```
|
||||
Search: 0 * * * * (hourly)
|
||||
Apply: 0 */6 * * * (every 6 hours)
|
||||
```
|
||||
|
||||
## Running manually
|
||||
```bash
|
||||
KERNEL_API_KEY=your_key node job_searcher.mjs # search now
|
||||
KERNEL_API_KEY=your_key node job_applier.mjs # apply now
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
**JobSearcher** (hourly):
|
||||
1. Searches LinkedIn + Wellfound with your configured keywords
|
||||
2. Filters out excluded roles/companies
|
||||
3. Adds new jobs to `data/jobs_queue.json`
|
||||
4. Sends Telegram: "Found X new jobs"
|
||||
**Search** — runs your keyword searches on LinkedIn and Wellfound, paginates/scrolls through results, filters exclusions, deduplicates, and queues new jobs.
|
||||
|
||||
**JobApplier** (every 6 hours):
|
||||
1. Reads queue for `new` + `needs_answer` jobs
|
||||
2. LinkedIn: navigates two-panel search view, clicks Easy Apply, fills form, submits
|
||||
3. Wellfound: navigates to job, fills profile, submits
|
||||
4. On unknown question → Telegrams you → saves answer → retries next run
|
||||
5. Sends summary when done
|
||||
**Apply** — picks up queued jobs, opens stealth browser sessions, fills forms using your profile + learned answers, and submits. Detects and skips honeypots, recruiter-only listings, and external ATS. Retries failed jobs automatically (default 2 retries).
|
||||
|
||||
## Mode A vs Mode B
|
||||
Set in `config/settings.json` → `"mode": "A"` or `"B"`
|
||||
|
||||
- **A**: Fully automatic. No intervention needed.
|
||||
- **B**: Applier sends you the queue 30 min before running. You can flag jobs to skip before it fires.
|
||||
**Learn** — on unknown questions, messages you on Telegram. You reply, the answer is saved to `answers.json` with regex pattern matching, and the job is retried next run.
|
||||
|
||||
## File structure
|
||||
|
||||
```
|
||||
claw-apply/
|
||||
├── job_searcher.mjs search agent
|
||||
├── job_applier.mjs apply agent
|
||||
├── setup.mjs setup wizard
|
||||
├── job_searcher.mjs Search agent
|
||||
├── job_applier.mjs Apply agent
|
||||
├── setup.mjs Setup wizard
|
||||
├── lib/
|
||||
│ ├── browser.mjs Kernel/Playwright factory
|
||||
│ ├── form_filler.mjs generic form filling
|
||||
│ ├── linkedin.mjs LinkedIn search + apply
|
||||
│ ├── wellfound.mjs Wellfound search + apply
|
||||
│ ├── queue.mjs queue management
|
||||
│ └── notify.mjs Telegram notifications
|
||||
│ ├── constants.mjs Shared constants
|
||||
│ ├── browser.mjs Kernel/Playwright browser factory
|
||||
│ ├── form_filler.mjs Form filling with pattern matching
|
||||
│ ├── linkedin.mjs LinkedIn search + Easy Apply
|
||||
│ ├── wellfound.mjs Wellfound search + apply
|
||||
│ ├── queue.mjs Job queue + config management
|
||||
│ └── notify.mjs Telegram notifications
|
||||
├── config/
|
||||
│ ├── profile.json ← fill this in
|
||||
│ ├── search_config.json ← fill this in
|
||||
│ ├── answers.json ← auto-grows over time
|
||||
│ └── settings.json ← fill this in
|
||||
│ ├── *.example.json Templates (committed)
|
||||
│ └── *.json Your config (gitignored)
|
||||
└── data/
|
||||
├── jobs_queue.json auto-managed
|
||||
└── applications_log.json auto-managed
|
||||
├── jobs_queue.json Job queue (auto-managed)
|
||||
└── applications_log.json History (auto-managed)
|
||||
```
|
||||
|
||||
## answers.json — self-learning Q&A bank
|
||||
When the applier hits a question it can't answer, it messages you on Telegram.
|
||||
You reply. The answer is saved to `config/answers.json` and used forever after.
|
||||
## answers.json — self-learning Q&A
|
||||
|
||||
When the applier can't answer a question, it messages you. Your reply is saved and reused:
|
||||
|
||||
Pattern matching is regex-friendly:
|
||||
```json
|
||||
[
|
||||
{ "pattern": "quota attainment", "answer": "1.12" },
|
||||
@@ -115,3 +114,5 @@ Pattern matching is regex-friendly:
|
||||
{ "pattern": "1.*10.*scale", "answer": "9" }
|
||||
]
|
||||
```
|
||||
|
||||
Patterns are matched case-insensitively and support regex.
|
||||
|
||||
Reference in New Issue
Block a user