Metadata-Version: 2.4
Name: karyab
Version: 9.0.2
Summary: Personal job-finding automation: fetch, rank, track job postings.
Project-URL: Repository, https://codeberg.org/maxagahi/karyab
Author: maxagahi
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: automation,cli,job-search,jobs
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business
Requires-Python: >=3.11
Requires-Dist: anthropic>=0.40
Requires-Dist: docxtpl>=0.18
Requires-Dist: fastapi>=0.110
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1.6
Requires-Dist: markdown>=3.6
Requires-Dist: mcp>=1.0
Requires-Dist: msal>=1.28
Requires-Dist: platformdirs>=4.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pypdf>=4.0
Requires-Dist: python-docx>=1.0
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: tomlkit>=0.13
Requires-Dist: typst>=0.13
Requires-Dist: uvicorn[standard]>=0.29
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pre-commit>=3.8; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# 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](AGENTS.md) and
> [docs/ARCHITECTURE.md](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

```bash
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:

```bash
karyab mcp-setup --target claude|opencode|both
```

## Quickstart

```bash
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.toml` into Claude (or any LLM), describe the jobs you
> want, and have it generate your `~/.config/karyab/config.toml` filters 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):**

```toml
[ranker]
backend = "manual"
```

Then register the MCP server and score from Claude Code:

```bash
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)

```toml
[sources.email]
enabled = true
imap_host = "outlook.office365.com"
folder    = "INBOX"
username  = "you@outlook.com"
auth      = "oauth"
```

Authenticate once:

```bash
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:

```bash
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

```bash
karyab update    # upgrade via pipx, or prints manual guidance if not installed via pipx
```

## Development

```bash
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](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](docs/ARCHITECTURE.md) for the full design.

## License

[Apache-2.0](LICENSE).
