wkjobs
Officialby WeKruit
README.md
# wkjobs
Search public job listings from your terminal and connect your results to the same canonical WeKruit candidate profile used by wekruit-pa.
```bash
npx wkjobs search "founding engineer" --location "San Francisco"
npx wkjobs login # Continue with LinkedIn → WeKruit
npx wkjobs resume add ./resume.pdf --yes
claude mcp add wkjobs -- npx wkjobs mcp
```
## What is implemented
- anonymous LinkedIn guest job search with normalized JSON or a terminal table;
- WeKruit device-login client that opens a WeKruit page and requires LinkedIn OIDC;
- private local storage (mode `0600`) for the scoped WeKruit token only;
- PDF/DOCX content sniffing, 5 MiB cap, SHA-256 hashing, and canonical resume-upload client;
- MCP tools: `search_jobs`, `auth_status`, and `get_resume` status;
- deterministic mock backend and fixture-only tests.
The production device and resume endpoints require the corresponding wekruit-pa backend deployment. Until that is deployed, use the mock server:
```bash
npm install
npm run mock:api
WKJOBS_API_BASE=http://127.0.0.1:8787 npm run dev -- login
```
The browser page in the mock simulates LinkedIn consent and never contacts LinkedIn.
## Commands
```text
wkjobs search "<query>" [--location X] [--remote] [--hours 72] [--limit N]
wkjobs login Connect LinkedIn to a canonical WeKruit user
wkjobs connect Alias for login
wkjobs resume add <pdf-or-docx> Store on that canonical WeKruit profile
wkjobs status Show account and resume status
wkjobs mcp Run the MCP server over stdio
```
Global flags: `--json`, `--yes`, and `--quiet`.
## Identity and data model
wkjobs has no separate user database. Login is WeKruit authentication backed by LinkedIn OIDC. New people become normal WeKruit candidates; returning people resolve to their existing canonical candidate. A resume enters the existing private original → artifact → parsed resume → user tags/profile → Claire continuation pipeline.
The CLI never asks for a LinkedIn password and never receives a LinkedIn OAuth token.
`wkjobs login` offers a second, separate step: connecting your own LinkedIn session so results can be personalized. LinkedIn OIDC grants only `openid profile email` and no job-search API, so personalized results require your browser session rather than an API token. If you accept, wkjobs stores the `li_at` and `JSESSIONID` cookies from your own sign-in — plus the user agent that minted them — in `~/.wkjobs/credentials.json` at mode `0600`. They never leave your machine and are never sent to WeKruit. LinkedIn's terms do not permit automated access, so requests are paced conservatively; the risk to your account is small but not zero.
This step is always opt-in. Declining leaves you on public guest listings, which need no login. `--no-linkedin` skips it, non-interactive runs skip it by default (the generic `--yes` does **not** grant it), and `wkjobs logout --linkedin` deletes the stored session.
See [the corrected plan](docs/CORRECTED_IMPLEMENTATION_PLAN.md) and [the production backend contract](docs/WEKRUIT_BACKEND_CONTRACT.md).
## Data and privacy
`search` sends the search terms needed to retrieve public LinkedIn guest results. `login` sends a device-flow request to WeKruit and completes LinkedIn consent in the browser on a WeKruit-owned page. `resume add` clearly discloses that the document will be stored in WeKruit's canonical candidate profile and may be used by Claire for matching.
Local credentials live at `~/.wkjobs/credentials.json` with mode `0600`. Override the directory only with an absolute `WKJOBS_HOME` path. Set `WKJOBS_API_BASE` to select a development backend.
## Development
```bash
npm install
npm run check
npm run dev -- search "typescript" --json
```
CI never logs into LinkedIn and never calls LinkedIn live endpoints; it uses recorded HTML fixtures.
## License
MIT
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues