Metadata-Version: 2.4
Name: pushcv-ui
Version: 0.1.0
Summary: pushcv-ui — a minimalist local web UI for pushcv. Same workspace, same SQLite, zero cloud.
Project-URL: Homepage, https://github.com/notnotparas/pushcv-ui
Project-URL: Repository, https://github.com/notnotparas/pushcv-ui
Author: pushcv contributors
License: MIT
License-File: LICENSE
Keywords: job-tracker,jobs,kanban,local-first,pushcv
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: fastapi<1,>=0.115
Requires-Dist: pushcv<0.3,>=0.2
Requires-Dist: uvicorn<1,>=0.30
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest<9,>=8; extra == 'dev'
Description-Content-Type: text/markdown

# pushcv-ui

A **minimalist local web UI** for [pushcv](https://github.com/notnotparas/pushcv-cli)
— your job-application pipeline as a clean Kanban board in the browser, with
the same local-first guarantees as the CLI: same folder, same `pushcv.db`,
bound to `127.0.0.1`, no accounts, no telemetry, no CDN assets.

pushcv-cli stays terminal-only by design; this is a separate, optional
frontend for people who want a visual board. Both frontends share one service
layer (`pushcv.core`), so anything you do here shows up in `pushcv status`
and vice versa.

## What you get

- 📋 The four-column pipeline (Drafting → Applied → Interviewing → Closed)
  with the same position numbers `[1]`, `[2]`, … the CLI uses.
- 🔎 Paste a posting URL (LinkedIn, Greenhouse, Lever, SmartRecruiters, or any
  page with JobPosting metadata) → preview → track.
- 📄 A detail drawer per job: move between statuses, dated notes timeline,
  full description, posting + apply links, delete.
- ⏱ Follow-up nudges on stale applications, salary estimates when the CLI has
  filled them in.
- ✍️ A built-in **profile editor** — view and edit the `profile.md` the AI
  tailors resumes from, with a first-run template and ⌘S/Ctrl+S save.
- ✨ **AI features guided, not hidden** — each job shows copyable
  `pushcv draft` commands, lists the drafts they generate (view them right in
  the drawer), and nudges you when your profile is still the blank template.
  A "local AI setup" explainer covers the Lemonade/`.env` details.
- 🌗 Light and dark, following your system preference. One self-contained HTML
  page — no build step, no external fonts or scripts.

## Install & run

With [uv](https://docs.astral.sh/uv/) (recommended — no install at all):

```bash
cd ~/job-hunt          # the folder where your pushcv.db lives
uvx pushcv-ui
```

Or install it with [pipx](https://pipx.pypa.io/):

```bash
pipx install pushcv-ui --include-deps
cd ~/job-hunt
pushcv-ui
```

> **Why `--include-deps`?** `pushcv-ui` depends on the
> [pushcv CLI](https://github.com/notnotparas/pushcv-cli) — installing the UI
> always brings the CLI along, and the AI features (`pushcv draft`, salary
> estimates) run through it. The flag puts the `pushcv` command on your PATH
> too. Without it, install the CLI separately: `pipx install pushcv` — the two
> share data through the workspace folder either way.

The server starts on `http://127.0.0.1:7878/` and opens your browser. Options:

```text
pushcv-ui [--dir PATH] [--port N] [--no-browser]
```

## Setting up the AI features

Resume/cover-letter drafting and AI salary synthesis are **pushcv CLI
features** — the UI guides you to them rather than reimplementing them.
Installing `pushcv-ui` already brought the CLI along; to use the AI:

1. **Run a local model.** Any OpenAI-compatible inference server works — e.g.
   [Lemonade](https://github.com/lemonade-sdk/lemonade) — serving a chat
   model (the default model id is `Qwen3-8B-GGUF`; override with
   `pushcv draft <n> --model <id>`). pushcv talks to
   `http://localhost:13305/v1` by default; point it elsewhere with
   `PUSHCV_AI_BASE` in a `.env` file in your job-hunt folder.
2. **Fill in your profile** — click *Profile* in the UI header. It's the
   source of truth the AI tailors from; drafts sign off with the name you put
   there, and the prompts never invent experience you didn't list.
3. **Copy the command from the job's drawer** (e.g. `pushcv draft 3`) and run
   it in a terminal *in the same folder*. The generated draft appears in the
   job's drawer — and in `drafts/` — when it's done.

Everything stays on your machine: the model is local, and nothing is sent to
a remote provider. Full details live in the
[pushcv README](https://github.com/notnotparas/pushcv-cli#readme).

## Local-first, like the CLI

- Binds to `127.0.0.1` only — nothing is reachable from your network — and
  rejects non-localhost `Host` headers (DNS-rebinding protection).
- Operates on the directory you start it in (or `--dir`); all writes go to the
  same SQLite file the CLI uses.
- The AI features *execute* in the CLI — the UI hands you the exact command
  for the job you're looking at, and the results (drafts, estimates) appear
  on the board the moment they exist. Same folder, same `pushcv.db`, one
  source of truth.

## Development

```bash
git clone https://github.com/notnotparas/pushcv-ui.git && cd pushcv-ui
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"         # resolves pushcv from PyPI
pushcv-ui --dir /tmp/demo
```

Hacking on the UI and the CLI/service layer at the same time? Install the
sibling checkout editably first: `pip install -e ../pushcv-cli`.

Layout:

```text
pushcv-ui/
├── pyproject.toml
├── tests/                 # API tests over a throwaway workspace
└── src/pushcv_ui/
    ├── server.py          # FastAPI over pushcv.core.Workspace (localhost only)
    └── static/index.html  # the whole UI — one hand-written page, zero deps
```

## License

[MIT](./LICENSE) © pushcv contributors
