Personal job-finding automation: fetch, rank, track job postings.
Project description
karyab
kaaryab (Persian کاریاب, "job finder") — personal job-hunting automation for the terminal.
karyab fetches job postings from multiple sources, ranks them against your profile, builds a daily shortlist you can act on, and tracks the applications you submit — nudging you to follow up when a posting goes quiet.
Privacy by design. This repository contains code only. Your personal data — profile, CV, API keys, the application database — never lives in the repo. It lives under your XDG directories (
~/.config/karyab,~/.local/share/karyab). See AGENTS.md and docs/ARCHITECTURE.md.
Requirements
- Python 3.11+
- A container runtime for the web UI — podman (recommended) or docker.
- Optional ranker tooling, depending on the backend you choose: Claude Code, opencode, ollama, or an Anthropic API key. See the in-app Help page for the full per-backend setup.
Install
pipx install karyab
After installing, register the MCP server with your coding agent and read the
in-app Help page (/help, linked in the nav) for full ranker-backend and
email/LinkedIn-alert setup:
karyab mcp-setup --target claude|opencode|both
Quickstart
karyab setup # guided onboarding: config, email auth, first fetch
karyab run # fetch → rank → digest (the daily pipeline)
karyab start # web UI at http://127.0.0.1:16666
Tip — let an LLM fill your config. The trickiest part is writing good filters (target roles, must-have keywords, source tokens, the ranker profile). Paste
config.example.tomlinto Claude (or any LLM), describe the jobs you want, and have it generate your~/.config/karyab/config.tomlfilters and[profile]. With the MCP server registered (karyab mcp register), Claude can also read your unranked jobs and tune the filters as you go.
Commands
| Command | Description |
|---|---|
karyab setup |
Guided onboarding: init, config, email auth, first fetch |
karyab config |
Create config + secrets from templates; open in $EDITOR |
karyab run |
Fetch → rank → digest (full daily pipeline) |
karyab fetch |
Fetch + normalize + store postings from enabled sources |
karyab rank |
Score stored jobs for fit against your profile |
karyab digest |
Render the daily Markdown shortlist |
karyab followups |
List applications gone quiet (stale by configured threshold) |
karyab apply <id> |
Mark a job as applied |
karyab start |
Build/pull + run the web-UI container |
karyab stop |
Stop the web-UI container |
karyab logs |
Tail the web-UI container logs |
karyab email <auth|test|list|fetch|send> |
Manage email accounts (auth, IMAP test, list, fetch, send) |
karyab schedule <install|status|logs|uninstall> |
Manage the systemd user timer |
karyab backup <create|list|restore> |
Create / list / restore database+config backups |
karyab db test |
Test database integrity and table presence |
karyab mcp <run|register> |
Run the MCP stdio server / register it with Claude Code |
karyab update |
Upgrade karyab via pipx (or print manual guidance) |
karyab init |
Create XDG dirs, copy example config, init database |
karyab --version |
Print installed version |
Run karyab <command> --help for per-command options. For grouped commands,
run karyab <group> --help (e.g. karyab email --help) for per-group options.
Ranking
Configure under [ranker] in ~/.config/karyab/config.toml. Five backends:
| Backend | How it works |
|---|---|
anthropic |
Anthropic API (default; requires ANTHROPIC_API_KEY or key in secrets) |
ollama |
Local Ollama instance — fully offline, no API key |
manual |
No autonomous scoring; use karyab mcp register + Claude Code MCP tools to score interactively |
claude_cli |
Shells out to the claude CLI — uses your Claude subscription, no extra key |
opencode |
Shells out to the opencode CLI — requires ANTHROPIC_API_KEY |
Manual ranking (no API key, no subscription needed for the ranker itself):
[ranker]
backend = "manual"
Then register the MCP server and score from Claude Code:
karyab mcp register
# In Claude Code: use get_profile, list_unranked_jobs, set_job_rank
karyab digest # build shortlist from scores you set
Sources
- ATS public boards: Greenhouse, Lever, Ashby, Teamtailor — direct employer feeds, best signal
- Aggregators: Adzuna, The Muse, Remotive
- Remote boards: Remote OK, Arbeitnow, We Work Remotely
- Email alerts (IMAP): LinkedIn / Indeed job-alert emails via IMAP — no scraping, no ToS risk
No LinkedIn/Indeed scraping. Against their ToS, fragile, account-ban risk. Set up email job-alerts on those sites instead; karyab reads the alert emails.
Microsoft / Outlook email (OAuth2)
[sources.email]
enabled = true
imap_host = "outlook.office365.com"
folder = "INBOX"
username = "you@outlook.com"
auth = "oauth"
Authenticate once:
karyab email auth
# Prints a URL and short code. Open the URL, enter the code.
# Subsequent fetches refresh the token silently.
Scheduling
Install a systemd user timer for daily automation:
karyab schedule install # enable daily fetch timer
karyab schedule status # check timer state
karyab schedule logs # tail the fetch service logs
karyab schedule uninstall # remove timer
Update
karyab update # upgrade via pipx, or prints manual guidance if not installed via pipx
Development
git clone https://codeberg.org/maxagahi/karyab
cd karyab
make dev # create .venv + install dev+runtime deps + git hooks
make test # run test suite
make lint # ruff check
make typecheck # mypy src
make check # pre-commit run --all-files (lint, fmt, type, secret-scan)
CI runs on Forgejo (.forgejo/workflows/). Release: bump the version in
pyproject.toml, push a vX.Y.Z tag — the pipeline publishes to PyPI and
builds a container image automatically.
Contributing / Agents
AGENTS.md is the contributor + AI-agent manual: project layout,
the bot git/PR workflow (Codeberg/Forgejo, not gh), and the privacy rule
(no personal data in the repo — gitleaks enforces it).
Any PR that touches code under src/karyab/ must bump the version in
pyproject.toml and add a CHANGELOG.md (Unreleased) entry. CI enforces both
(verify-version-bump); the same checks run locally at pre-push.
Architecture
sources ──▶ normalize ──▶ store ──▶ rank ──▶ digest ──▶ you apply
│
track ◀───┘
│
follow-up nudges
Local-first, SQLite-backed pipeline. Each stage has a narrow contract; stages run independently (a timer fetches; you rank and read the digest later). See docs/ARCHITECTURE.md for the full design.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file karyab-10.1.0.tar.gz.
File metadata
- Download URL: karyab-10.1.0.tar.gz
- Upload date:
- Size: 479.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c92f49160223721041fdbf560a2ffe7fab9079a94bb89b60acb45b2accdc791b
|
|
| MD5 |
ab5e5e48069c042abca10f059f282f0b
|
|
| BLAKE2b-256 |
427b79d2a56ddcbc94abb895f7cefcc678ad12f0a44d556db729c2beedca84d4
|
File details
Details for the file karyab-10.1.0-py3-none-any.whl.
File metadata
- Download URL: karyab-10.1.0-py3-none-any.whl
- Upload date:
- Size: 296.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4dadac19a56a81e3b590b4182e08ccfbbfc36381b44e2f43c3096e47be8d43c
|
|
| MD5 |
d1db4c44a235e2a4d1595a80d2a1cbde
|
|
| BLAKE2b-256 |
d1db1dec334deebe8f2eb0cdddc060e130ff2fa034a6558bf3dd3616f96a9782
|