Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install dependencies
run: npm ci

- name: Run packaging tests
run: npm test

- name: Run installed skill tests
run: npm run test:skills

- name: Release-safety gate
run: node scripts/check-release-safety.mjs

- name: Skill-closure verification
run: node scripts/verify-skill-closure.mjs

- name: Dependency-matrix verification
run: node scripts/verify-dependency-matrix.mjs

- name: Validate compose.yaml
run: docker compose config --quiet

- name: Check doc commands
run: node scripts/check-doc-commands.mjs

- name: Check required doc sections
run: node scripts/check-required-doc-sections.mjs

compose-rehearsal:
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v4

- name: Run compose rehearsal
run: bash scripts/rehearse-compose.sh
timeout-minutes: 10
91 changes: 91 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Release

on:
push:
tags: ['v*']

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
outputs:
archive: ${{ steps.archive.outputs.path }}
checksum: ${{ steps.checksum.outputs.sha256 }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install dependencies
run: npm ci

- name: Run packaging tests
run: npm test

- name: Run installed skill tests
run: npm run test:skills

- name: Release verification (source tree)
run: npm run verify:release

- name: Build source archive
id: archive
run: |
ARCHIVE="job-hunter-${GITHUB_REF_NAME}.tar.gz"
git archive --prefix="job-hunter-${GITHUB_REF_NAME}/" -o "$ARCHIVE" HEAD
echo "path=$ARCHIVE" >> "$GITHUB_OUTPUT"

- name: SHA-256 checksum
id: checksum
run: |
ARCHIVE="${{ steps.archive.outputs.path }}"
SHA=$(sha256sum "$ARCHIVE" | awk '{print $1}')
echo "sha256=$SHA" >> "$GITHUB_OUTPUT"
echo "$SHA $ARCHIVE" > "${ARCHIVE}.sha256"

- name: Extract and safety-scan archive
run: |
ARCHIVE="${{ steps.archive.outputs.path }}"
mkdir /tmp/archive-scan
tar -xzf "$ARCHIVE" -C /tmp/archive-scan
node scripts/check-release-safety.mjs /tmp/archive-scan/job-hunter-${GITHUB_REF_NAME}

- name: Upload archive
uses: actions/upload-artifact@v4
with:
name: source-archive
path: ${{ steps.archive.outputs.path }}

- name: Upload checksum
uses: actions/upload-artifact@v4
with:
name: source-archive-sha256
path: ${{ steps.archive.outputs.path }}.sha256

release:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download archive
uses: actions/download-artifact@v4
with:
name: source-archive

- name: Download checksum
uses: actions/download-artifact@v4
with:
name: source-archive-sha256

- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
files: |
*.tar.gz
*.sha256
draft: true
61 changes: 61 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Dependencies
node_modules/

# Python
__pycache__/
*.pyc
.venv/
uv.lock

# Runtime artifacts
*.sqlite
*.sqlite3
*.docx
*.pdf
*.xlsx
*.csv
!examples/**/*.docx
personal-info-cache.json
apply_logs/
logs/
backups/
screenshots/
*.png
*.jpg
*.jpeg
*.webp
*.log

# Browser state
chromium-profile/
chromium_profile/
selenium_chrome_profile/
searxng/
*.bak

# OS
.DS_Store
Thumbs.db

# IDE
.idea/
.vscode/
*.swp
*.swo

# Environment
.env
.env.local
.env.*.local

# Job-hunter runtime (never tracked)
.job-hunter/

# Agent evidence (local, never published)
agent-output/

# Build/release
dist/
tmp/
*.tar.gz
*.zip
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025-2026 Deviad

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
125 changes: 125 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Job Hunter

Complete job-search pipeline for [Pi Agent](https://github.com/earendil-works/pi) — search, score, salary enrichment, and assisted applications.

## Prerequisites

| Layer | Requirement | Stage |
|-------|-------------|-------|
| Runtime | Node.js ≥ 22, `uv` ≥ 0.4 | Install |
| Code | `npm ci` in repo root | Install |
| Workspace | `$JOBHUNTER_HOME` (default `~/.job-hunter`) with `jobhunter.sqlite`, `CV.docx`, `personal-info-cache.json` | Init |
| Browser | Chromium CDP on `127.0.0.1:9225` (Selenium container) | Search, Apply |
| Search | SearXNG on `127.0.0.1:8888` | Discover |
| Vision (optional) | LM Studio on `127.0.0.1:1234` with Qwen VLM | CAPTCHA, Debug |
| MCP (optional) | Obscura, Apple Mail MCP servers | Browse, Outreach |

Host tools (`docker`, `sqlite3`, `python3`) must be installed and on `PATH` — the doctor (`jh-doctor`) diagnoses which are missing but does not install them.

## Installation

```bash
git clone https://github.com/Deviad/job-hunter.git && cd job-hunter
npm ci
node scripts/install.mjs # copies skills into ${PI_AGENT_HOME:-~/.pi/agent}/skills/
node scripts/install.mjs --dry-run # preview without writing
```

Re-run is idempotent and never overwrites `CV.docx`, `personal-info-cache.json`, or `jobhunter.sqlite`.

## Initialization

```bash
node ~/.pi/agent/skills/job-hunter/scripts/jh-init.mjs
```

Before applying, populate `~/.job-hunter/CV.docx` and the `profile.firstName`, `profile.lastName`, `profile.email`, and `profile.phone` fields in `~/.job-hunter/personal-info-cache.json`. Application helpers fail closed when required identity fields are absent; the repository contains no maintainer identity defaults.

### Doctor

Run the doctor before each search or application session. It distinguishes required failures from optional degraded capabilities.

```bash
node ~/.pi/agent/skills/job-hunter/scripts/jh-doctor.mjs
```

## External Services

Start Selenium and SearXNG:

```bash
export SEARXNG_SECRET="$(node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))")"
docker compose up -d
bash scripts/rehearse-compose.sh # isolated health-check rehearsal with teardown
```

See `docs/prerequisites.md` for full host-tool list and `docs/security-and-privacy.md` for security boundaries.

## Workflow

### Search

```bash
node ~/.pi/agent/skills/job-hunter/scripts/jh-search.mjs --source linkedin --country GB --role "Software Engineer"
node ~/.pi/agent/skills/job-hunter/scripts/jh-search.mjs --source indeed --country GB --query "Software Engineer"
node ~/.pi/agent/skills/job-hunter/scripts/jh-discover.mjs --locations "United Kingdom" --queries "Software Engineer"
```

### Score

Ask Pi to score the saved jobs. The `job-match-scorer` skill reads the user's CV and workspace profile rather than repository defaults.

### Salary

```bash
node ~/.pi/agent/skills/salary-calculator/scripts/enrich-job-salary.mjs --db ~/.job-hunter/jobhunter.sqlite --all-unsalaried
```

### Apply

Ask Pi to apply to a scored job. The `auto-job-application` skill uses the user's local CV, cache, and authenticated Chromium session; there is no repository-level submit command.

### Pipeline status and backup

```bash
node ~/.pi/agent/skills/job-hunter/scripts/jh-status.mjs
node ~/.pi/agent/skills/job-hunter/scripts/jh-backup.mjs
```

## Update

```bash
git pull && npm ci && node scripts/install.mjs
```

## Uninstall

```bash
node scripts/install.mjs --uninstall
```

Removes only files recorded in the installation manifest. User data (`CV.docx`, DB, cache) is untouched.

## Troubleshooting

```bash
node ~/.pi/agent/skills/job-hunter/scripts/jh-doctor.mjs # full diagnostic
```

Common issues:

- **CDP not reachable**: ensure `docker compose up -d` ran and `curl -s http://127.0.0.1:9225/json/version` returns JSON.
- **SearXNG 502**: SearXNG needs a few seconds after container start; retry after 5s.
- **better-sqlite3 build failure**: ensure `python3` and a C compiler (Xcode CLT on macOS) are installed.
- **MCP "Not connected"**: run the repair skill or `bash scripts/rehearse-compose.sh` to verify transport.

## Security and Privacy

- All job-search data, credentials, and browser sessions stay on your machine.
- The installer never reads or transmits personal files.
- Authenticated browser sessions (LinkedIn, Indeed) belong to you — this project does not bypass CAPTCHA, MFA, or site access controls.
- See `docs/security-and-privacy.md` for the full policy.

## License

MIT — see `LICENSE`.
Loading
Loading