Metadata-Version: 2.5
Name: hiair-cli
Version: 0.6.1
Summary: Run HiAir applies in your own Chrome
Project-URL: Homepage, https://hiair.ai
Project-URL: Repository, https://github.com/hiair-ai/hiair-cli
Project-URL: Issues, https://github.com/hiair-ai/hiair-cli/issues
Author-email: HiAir <admin@hiair.ai>
License: MIT
License-File: LICENSE
Keywords: apply,chrome,hiair,jobs
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27.0
Requires-Dist: playwright<2,>=1.62
Provides-Extra: gui
Requires-Dist: pywebview<7,>=5.1; extra == 'gui'
Description-Content-Type: text/markdown

# HiAir CLI

Fill job applications in **your** Chrome, then store them in the HiAir tracker.

## Install

You need [Python 3.11+](https://www.python.org/downloads/) and [pipx](https://pipx.pypa.io/). Google Chrome must be installed for applies.

```bash
pipx install hiair-cli
# or: uv tool install hiair-cli

hiair login
```

`hiair login` offers to install the login worker for you (or run
`hiair service install` yourself later). If something misbehaves, run
`hiair doctor`.

After that, the worker starts at login. Queue jobs from the website or copilot; when one arrives, this Mac opens a disposable Chrome, fills the application, and writes the result back. Everyday Chrome can stay open. Logins in the HiAir window do not persist.

Closing a tab stops that application; closing the HiAir Chrome window stops all of
them. Stopped applications show as stopped in the app and their credits come back,
and the worker waits 30 seconds before opening Chrome for the next queued job.
Ctrl-C in a foreground `hiair apply` stops the in-flight applications the same way.

`hiair service` is macOS only. To watch a run in the foreground (any OS), use `hiair apply`.

### Several applications at once

`hiair apply` fills up to four queued applications at the same time, each in its own tab of
the one HiAir Chrome window, so a batch queued from the site finishes in a fraction of the time.
`hiair apply --parallel 6` raises the limit (max 8), and `--parallel 1` goes back to one at a
time. The login worker takes its default from `HIAIR_APPLY_PARALLEL` **as set when you run
`hiair service install`** — launchd agents do not inherit your shell, so exporting it afterwards
only affects `hiair apply` in a terminal:

```bash
HIAIR_APPLY_PARALLEL=6 hiair service install
```

The server still hands out one application per company career site at a time, so the parallelism
is across companies. When one tab needs you, it comes to the front and the terminal prompt is for
that tab only; the others keep working.

## When the agent needs you

If the form asks something your profile cannot answer, shows a captcha, sends
you a code, or wants you to sign in, the apply **pauses with the page still
open** in the HiAir Chrome window. You get a desktop notification, the field is
highlighted, and `hiair apply` prints what is needed. Then either:

- fix it in the browser and press **Enter** in the terminal,
- press **a** and type the answers in the terminal (the agent types them into
  the form), or
- press **s** if you clicked Submit yourself.

You can also answer from the HiAir website; the daemon notices and carries on.
If nothing happens for about 45 minutes the run falls back to "Needs you" on
the website and the page closes. The login service (no terminal) still pauses
and waits for the website.

## The device console

`hiair wakeup` opens a small native window showing everything at a glance:
pairing and backend connection, the login worker, the applications this Mac
is filling right now (with pauses that need you), health checks, and the
worker log. Pairing, unpairing, installing the login worker, and stopping a
running apply all work from the window too.

The applications feed is read from the worker log, which only the login
service writes — so install the worker (`hiair service install`) to see runs
there. A foreground `hiair apply` prints to its own terminal instead.

The Activity panel starts folded: the log can quote what a form asked you,
which on a job application means salary, sponsorship and EEO questions.
Choose **Show** to read it.

It needs the `gui` extra:

```bash
pipx install 'hiair-cli[gui]'
# already installed? add it with: pipx inject hiair-cli pywebview

hiair wakeup
```

## Driving it from your own agent

Search jobs and fetch personal matches without starting Chrome or the login worker:

```bash
hiair jobs search --company Google --limit 5 --json
hiair jobs matches --limit 5 --json
hiair jobs search --query backend --location Boston --sort date_added
hiair jobs companies --query google --json
hiair jobs get 'google:12345' --json
hiair jobs queue 'google:12345' --json
```

Search and matches both default to your profile's recommended order. They support
`--query`, repeatable `--company`, `--location`, and `--level`, `--salary-min`,
`--limit` (1–50, default 10), `--page` (default 1), and
`--sort recommended|date_added`. Company names resolve case-insensitively to exact
directory names; unknown or ambiguous names fail instead of widening the search.
Location filters use the API's comma-separated substring semantics; use a city name
when filtering by city. Level values use labels such as `"Senior Level"`.

All job commands accept `--api-url` and require pairing. Recommended searches need
profile information; complete your profile or explicitly choose `--sort date_added`.
The feed follows the website's applied/dismissed exclusions. Default output is
human-readable; `--json` returns the API's job/pagination data with diagnostics on
stderr. `jobs get` returns full job details.

`hiair jobs queue JOB_ID` queues an application for the paired user's CLI worker.
Use an actual ID from search or matches. It uses your saved application profile
and the normal credit rules, and an online worker can start filling immediately.
If the worker is offline, run `hiair apply` to process queued jobs. It never falls
back to a cloud browser. Repeat requests return an existing in-flight or successful
application without a second charge. The output includes the run ID and current
status; queueing is not confirmation that an application was submitted.

After installing the skill below, ask your coding agent “give me the top 5 jobs from
Google” or “what are my top 5 job matches.” The agent maps your request to these
commands. Existing users must update the CLI and rerun `hiair skill install` with
their original client/global/directory options to refresh the installed skill.

```bash
hiair skill install
```

asks which coding agent should load the skill — **Cursor**, **Claude**,
**ChatGPT** (Codex), **GitHub Copilot**, **Gemini**, or all of them — then
writes a self-contained [Agent Skill](https://agentskills.io) (`SKILL.md`)
into that agent's first-party skill folder. It teaches the agent the full
`hiair` command surface, so it can search jobs, fetch matches, check status, and run applies; it
assumes the CLI is already installed and paired as above.

This writes **skills**, not Cursor rules. Rules live in `.cursor/rules` as
`.mdc` files and are a different system.

| Agent | Project | Global (`--global`) |
| --- | --- | --- |
| Cursor | `.cursor/skills/hiair` | `~/.cursor/skills/hiair` |
| Claude | `.claude/skills/hiair` | `~/.claude/skills/hiair` |
| ChatGPT | `.agents/skills/hiair` | `~/.agents/skills/hiair` |
| GitHub Copilot | `.github/skills/hiair` | `~/.copilot/skills/hiair` |
| Gemini | `.gemini/skills/hiair` | `~/.gemini/skills/hiair` |

- `hiair skill install --client cursor` (or `claude`, `chatgpt`, `copilot`,
  `gemini`, `all`) skips the prompt. Repeat `--client` or comma-separate to
  pick several.
- `hiair skill install --global` writes the home-directory folder for each
  chosen agent, so every project sees it.
- `hiair skill install --dir path/to/skills/hiair` writes there instead, for an
  agent that isn't in the list.
- `hiair skill uninstall` (same flags) removes it again.

The source lives at [`src/hiair_cli/skills/hiair/SKILL.md`](src/hiair_cli/skills/hiair/SKILL.md).

## Updating

What changed in each release: [CHANGELOG.md](CHANGELOG.md).

The login worker keeps itself on the latest release: it checks PyPI a few
times a day and, only when no application is in flight, upgrades its pipx or
uv install and restarts on the new version.

**This is on by default**, deliberately — it is how a security fix reaches a
worker that nobody is watching. It is worth knowing what that means: the
worker installs whatever PyPI currently publishes as the latest `hiair-cli`,
running that package's install hooks as your user. Releases are published from
GitHub Actions with PyPI trusted publishing and carry PEP 740 attestations, so
a release can be traced to the workflow that built it — but neither pipx nor uv
verifies those at install time yet, so that is provenance you can check, not a
check the installer makes for you. If you would rather approve each update,
turn off **Automatic updates** in the console's settings; the version chip
still lights up when one is available.

To update by hand:

```bash
hiair update          # check PyPI and install the latest release
hiair update --check  # just check
```

The console window also shows when an update is available (the version chip
lights up) and can install it from the settings sheet.

```bash
hiair --version
hiair status
hiair service status
hiair service uninstall
```

## Where the token lives

Pairing stores a device token. On macOS it goes in the **Keychain** (look for
"HiAir device token"); elsewhere, and if the Keychain refuses it, it falls back
to `~/.hiair/credentials`, which is created `0600` inside a `0700` directory.

A token written by an older version moves to the Keychain the first time this
version reads it. **That move is one-way**: a copy of hiair older than this one
does not know to look in the Keychain, so it reports "not logged in" until you
run `hiair login` again. It only comes up if you downgrade, or run two installs
side by side (a checkout next to a released copy). The login worker no longer
turns that into a restart loop — it waits quietly and picks up the next pairing
by itself.

That token is only ever sent to the backend that issued it. If you point the
CLI somewhere else — `--api-url`, or `$HIAIR_API_URL` — it will refuse rather
than hand your token to another host. For a development backend you trust, set
`HIAIR_ALLOW_CUSTOM_API=1`.

`hiair logout` removes the token from this Mac *and* revokes it server-side. If
it cannot reach the server it says so rather than claiming success, because
nothing expires the token on its own — remove the device at
[hiair.ai](https://hiair.ai) to finish the job.

### Application email verification

Connect Gmail on your [HiAir profile](https://hiair.ai/profile). The application
worker can read verification emails automatically when Gmail is connected at the
start of a run. If an application has already paused for an emailed code, retry
lookup and hand the code to its worker with:

```bash
hiair inbox verify 513 --length 8 --json
```

Use the run ID returned by `jobs queue` and the code length shown by the employer.
This reads recent mail for that application and resumes its open form; it does
not print the code. `resumed: true` means the worker received it, not that the
application was submitted. Missing mail leaves the run paused. Expired Gmail
access requires reconnecting on your profile, then retrying. `--api-url` is
supported. Existing users must reinstall the bundled HiAir skill after updating.
