hirify-cli 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "hirify-cli",
3
+ "version": "0.4.1",
4
+ "description": "Hirify CLI for AI agents: browser sign-in, job feeds, search, reading a vacancy in full, contacts to apply to, and applying on Hirify.",
5
+ "bin": {
6
+ "hirify": "bin/hirify.js"
7
+ },
8
+ "scripts": {
9
+ "test": "node scripts/test.mjs",
10
+ "prepublishOnly": "node scripts/prepublish-check.mjs"
11
+ },
12
+ "type": "module",
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "files": [
17
+ "bin",
18
+ "skills",
19
+ "README.md",
20
+ "NOTICE"
21
+ ],
22
+ "keywords": [
23
+ "hirify",
24
+ "jobs",
25
+ "ai-agent",
26
+ "cli",
27
+ "job-search",
28
+ "mcp",
29
+ "skills"
30
+ ],
31
+ "homepage": "https://hirify.me",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/hirifyme/hirify-cli.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/hirifyme/hirify-cli/issues"
38
+ },
39
+ "license": "Apache-2.0"
40
+ }
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: hirify
3
+ description: Job search through Hirify - vacancies from the user's saved feeds, search across the board, reading a vacancy in full, the contact to apply to, applying on Hirify, and saved searches with delivery. Use when the user asks to find jobs, look at their feeds, pick roles that fit their profile, apply, or set up alerts. Triggers - "find jobs", "what is in my feed", "where do I apply", "apply to this", "hirify".
4
+ ---
5
+
6
+ # Hirify job search
7
+
8
+ Use the Hirify job board through the `hirify` CLI. This file gives the working order; `reference.md`
9
+ has every command in full, and `hirify intro` is the server's guide.
10
+
11
+ ## What stays here, and what you fetch
12
+
13
+ This installed file holds only stable rules. Fetch anything Hirify can change:
14
+
15
+ | What you need | Ask for it |
16
+ |---|---|
17
+ | Filter names and their values | `hirify filter guide` |
18
+ | Reveals, vacancy opens and applies left | `hirify account show` |
19
+ | Rate limits, plan, abilities | `hirify account show --json` |
20
+ | The commands that exist | `hirify --help`, `hirify <noun>` |
21
+
22
+ ## Two rules before anything else
23
+
24
+ **Lists are free. Three commands are metered, and they spend different things.**
25
+
26
+ - `vacancy read` spends one of the day's vacancy opens. Re-reading a vacancy the same day is free.
27
+ - `vacancy reveal` spends 1 reveal, and reveals are scarce. When they run out, reading still works.
28
+ - `vacancy apply` counts against a small daily allowance of its own and **cannot be taken back**. It
29
+ sends a real application, with the user's name and profile, to a person who will read it.
30
+
31
+ **`hirify account show` is the only place these numbers are true.** Read it before spending; never
32
+ state what is left from memory or plan a batch on a stale figure.
33
+
34
+ **Ask the user before every apply, and before anything that changes their account.** Reading needs
35
+ no permission. Sending, saving and configuring do.
36
+
37
+ ## Working order
38
+
39
+ ```bash
40
+ hirify account show
41
+ hirify feed list
42
+ hirify feed show <id>
43
+ hirify vacancy search "senior go"
44
+ hirify vacancy read <slug>
45
+ hirify vacancy reveal <slug>
46
+ hirify vacancy apply <slug>
47
+ ```
48
+
49
+ 1. `hirify account show` before revealing anything.
50
+ 2. Feeds first, search second. A feed is a filter the user built, so it already says what they want.
51
+ 3. Shortlist **from the cards**. They carry no contacts, and that is normal.
52
+ 4. `hirify vacancy read` the shortlist. The card is a headline; the text is where fit is decided, and
53
+ reading is cheap. Judging fit without reading is guessing.
54
+ 5. `hirify vacancy reveal` only what still fits after reading. A reveal spent at random is spent.
55
+ 6. Apply only after the user says yes, and read the rules below first.
56
+
57
+ ## Searching
58
+
59
+ `vacancy search` takes a phrase and any criterion the site's filter form can express, passed as an
60
+ option under its own name. `--limit` sets the page size and `--page` moves through pages; those two
61
+ are the CLI's own, not filters.
62
+
63
+ **`hirify filter guide` is the method and vocabulary, and the only source for either.** Do not guess
64
+ criterion names or values. The final search refuses an unknown criterion, while a misspelt value
65
+ can return an empty list that looks like an honest "nothing matches". If a server does not serve
66
+ the guide, it says so; then ask the user what to filter on.
67
+
68
+ 1. Read `hirify filter guide` and build a draft from the user's request or profile.
69
+ 2. Run `hirify api call filters.preview --data '{"filters":{...},"mode":"compact","per_page":20}'`.
70
+ 3. Inspect cards and `meta.total`; refine and preview again if they are empty, broad or irrelevant.
71
+ 4. Run `hirify vacancy search` with the validated criteria.
72
+
73
+ ## Applying
74
+
75
+ Two cases, two commands:
76
+
77
+ - **Hosted on Hirify** -> `hirify vacancy apply <slug>` sends the application through Hirify.
78
+ - **From somewhere else** -> `hirify vacancy reveal <slug>` gives the link or contact, and **the
79
+ user applies themselves**. `vacancy apply` refuses these and says so.
80
+
81
+ - **Ask first, every time, and show what you are about to send.** An application cannot be taken
82
+ back. Never apply to a list on a single "yes".
83
+ - **Never invent the cover letter.** Draft it from what the user actually said about themselves and
84
+ show them the draft; if they gave you nothing, ask rather than fill the gap.
85
+ - **Never choose the profile** when the user has several: `hirify profile list` lists them. With
86
+ exactly one profile it is chosen automatically.
87
+ - After a successful apply, say it was sent and stop. Nobody follows up: the recruiter replies where
88
+ they choose to, and Hirify does not track it.
89
+
90
+ ## Saved searches and delivery
91
+
92
+ These change the user's account, so the same rule holds: propose, get a yes, then do it.
93
+
94
+ ```bash
95
+ hirify feed create "<name>" --filters '<json>' # criteria: hirify filter guide
96
+ hirify feed deliver <id> --telegram | --no-telegram | --webhook <id> | --no-webhook
97
+ hirify webhook list
98
+ hirify webhook create "<name>" <url>
99
+ ```
100
+
101
+ `--filters` takes the same criteria as the site's filter form; read `hirify filter guide` first.
102
+ Creating a delivery endpoint returns a **secret shown once**: give it to the user immediately to
103
+ store, because it signs every delivery and cannot be shown again.
104
+
105
+ ## Telling Hirify something is broken
106
+
107
+ `hirify feedback send <bug|feature> "<title>" --body "<text>" [--vacancy <slug>]` sends a report,
108
+ free. Ask first, send the user's words rather than your own, and report that it was passed on: it
109
+ gives a ticket number or says there is none yet, nothing writes back, and no fix or date is promised.
110
+
111
+ ## When something goes wrong
112
+
113
+ **The message you were given is the truth; this is a map of the kinds, not strings to match.** Every
114
+ failure exits non-zero and writes one line to stderr. Read that line and tell the user what it says.
115
+
116
+ - **Not signed in**: ask the user to run `hirify login` (it opens a browser and needs a person -
117
+ never run it yourself). On a server with no browser: `hirify auth <key>`, key from
118
+ hirify.me/account/api-access.
119
+ - **Sign-in no longer good** (401): expired or revoked. Ask the user to run `hirify login` again.
120
+ - **No access** (403): the sign-in is missing an ability, or the plan does not cover agent access.
121
+ Abilities are fixed at sign-in, so a user who signed in before an ability existed signs in again.
122
+ - **A budget or the pace** (429): a metered action is used up - reveals, vacancy opens, or applies -
123
+ or commands came too fast. The message names which; feeds and search keep working. What is left:
124
+ `hirify account show`.
125
+ - **A refusal naming a length or a value** comes from the server: shorten what it named and send
126
+ again, do not argue with it or assume a bound.
127
+ - **`hirify <noun> has no verb "..."`**: the name does not exist and the message lists the verbs that
128
+ noun takes. Read the list rather than guessing again.
129
+
130
+ ## When no command fits
131
+
132
+ `hirify api call <capability-id> --data '<json>'` runs a capability by its id and prints the answer
133
+ as it comes back, so a job with no named command is a detour, not a dead end. `hirify --help` and
134
+ the server's own catalogue name the capabilities.
135
+
136
+ Reach for a named command first where one exists: it says what a call costs and what a refusal means,
137
+ and this one cannot. It will spend a reveal or send a real application just as readily, so the same
138
+ rule holds - ask the user before anything that sends, saves or configures.
@@ -0,0 +1,286 @@
1
+ # hirify CLI reference
2
+
3
+ Written for an agent. Every command, what it costs, what it answers, and how it refuses.
4
+
5
+ Commands are a noun and a verb: the noun is the thing you are working with, the verb is what you do
6
+ to it. `hirify <noun>` on its own lists the verbs that noun takes. `login`, `logout`, `auth` and
7
+ `intro` stay single words: they are not operations on a thing.
8
+
9
+ **This file describes the CLI, not the state of Hirify.** It is installed with the skill and never
10
+ updated afterwards, so it names no filter, no limit and no number that our side can change. Those
11
+ come from commands: `hirify filter guide` for filters, `hirify account show` for what is left,
12
+ `hirify account show --json` for the plan and the limits. Where this file would have quoted one, it
13
+ names the command instead.
14
+
15
+ Add `--json` to any command to get the server's payload verbatim instead of the text below.
16
+ `--fields a,b` narrows a compact answer to the fields you name and never adds one the answer did not
17
+ carry. Parse `--json`; do not parse the text, it is written for a person to read.
18
+
19
+ **Exit codes are stable.** `0` is success, `1` an ordinary error, and `2` means this Hirify speaks a
20
+ newer manifest than your CLI can read - update the CLI. Every failure also writes one line to stderr
21
+ beginning with `hirify: `. Branch on the code rather than on the message text.
22
+
23
+ Set `HIRIFY_DEBUG=1` in front of a command to also get the server's own answer on stderr. Use it
24
+ when you need to report a problem; the normal output never contains raw payloads.
25
+
26
+ ## Cost model
27
+
28
+ | Command | Cost | Reversible |
29
+ |---|---|---|
30
+ | `account show`, `feed list`, `feed show`, `vacancy search`, `profile list`, `webhook list` | free: they spend nothing | reading only |
31
+ | `vacancy read` | 1 vacancy open from a generous daily allowance, repeats the same day are free | reading only |
32
+ | `vacancy reveal` | 1 reveal, repeats on the same vacancy are free | reading only |
33
+ | `vacancy apply` | counts against a daily allowance of its own | **no**: a real application reaches a real person |
34
+ | `feed create`, `feed deliver`, `webhook create` | free | changes the user's account |
35
+ | `feedback send` | free | a ticket is filed |
36
+ | `filter guide` | free: it spends nothing | reading only |
37
+ | `api call` | whatever the capability it calls costs | whatever that capability does |
38
+
39
+ Free is not unlimited: every command is rate-limited, reading more loosely than searching. A burst
40
+ answers `429` and names the seconds to wait. The numbers are the server's and change without this
41
+ file: `hirify account show --json`, block `limits`.
42
+
43
+ Three budgets run out, and they are separate. Vacancy opens are the allowance `vacancy read` draws
44
+ on. Reveals are the scarce one. Applications have a daily allowance of their own - `vacancy apply`
45
+ is not the free step it looks like. All three are in `hirify account show`, and in
46
+ `hirify account show --json` under
47
+ `quota.read`, `quota.reveal` and `quota.apply`.
48
+
49
+ **No number for any of them is written in this file.** Each block carries `limit`, `used` and
50
+ `remaining` as the server currently has them; that is the only place they are true, and this file
51
+ outlives every change to them.
52
+
53
+ ## Signing in
54
+
55
+ `hirify login` opens a browser and needs a person. Never run it yourself: ask the user to run it.
56
+ It stores access in `~/.config/hirify/auth.json` (mode 600) and renews it without asking again.
57
+ `hirify logout` forgets it. On CI or a server: `hirify auth <key>`, or `HIRIFY_KEY` in the
58
+ environment, which wins over a stored sign-in.
59
+
60
+ Permissions are fixed when the user signs in and cannot be added afterwards. A 403 naming a missing
61
+ permission means the user signed in before that permission existed: they have to run `hirify login`
62
+ again.
63
+
64
+ ## Reading
65
+
66
+ ```bash
67
+ hirify account show
68
+ hirify feed list
69
+ hirify feed show <id> [--limit N] [--page N]
70
+ hirify vacancy search "<phrase>" [--<criterion> <value>]... [--limit N] [--page N]
71
+ ```
72
+
73
+ `account show` reports the plan, the reveals left, the vacancy opens left today, the applications
74
+ left today, and reveal usage over 7 and 30 days. Check it before spending any of the three. The
75
+ allowances come as one number each, not as a fraction.
76
+
77
+ `feed list` lists saved searches as `<id> <name>`, with `(off)` for an inactive one. `feed show
78
+ <id>` returns that feed's vacancies, using the criteria saved in the feed.
79
+
80
+ `vacancy search` is a conduit. The words are the phrase; every option is forwarded to the API under
81
+ the name you gave it, so the criteria are the server's and this CLI holds no copy of them to fall
82
+ behind. `--limit` is the page size and arrives as the API's `per_page`; `--json` steers the CLI and
83
+ is never sent. An option repeated is joined with a comma, which is how the site sends a criterion
84
+ with several values.
85
+
86
+ **The criteria and the method come from `hirify filter guide`, and only from there.** Do not guess
87
+ names or values. The final search refuses an unknown criterion, while a misspelt value can return
88
+ an empty list that looks like an honest answer.
89
+
90
+ Both `feed show` and `vacancy search` page with `--page N`. The last line of a list says which page
91
+ you are on and offers the next one when there may be another.
92
+
93
+ Vacancy cards print as:
94
+
95
+ ```
96
+ <slug>
97
+ <title> · <company or "company hidden">
98
+ [<remote> · <format> · <employment> · <english> · <salary> · verified]
99
+ ```
100
+
101
+ Cards never carry contacts. `company hidden` means the name is revealed by `vacancy reveal`, not
102
+ that the field is broken.
103
+
104
+ ## filter guide: what search can filter on
105
+
106
+ ```bash
107
+ hirify filter guide
108
+ ```
109
+
110
+ Prints the filter guide the server writes: which criteria search accepts, what their values are,
111
+ and the method for turning what a person wants into a filter that works. Free, and it needs
112
+ `agent:read` like the other reading commands.
113
+
114
+ The server derives it from the same source the site's own search reads, so it cannot fall behind
115
+ the search. That is the whole point: nothing in this package writes filter names down, because a
116
+ list written here goes stale silently and an agent acts on it without knowing.
117
+
118
+ The guide requires a preview before a filter is used. For the CLI, invoke the preview capability
119
+ through the generic command:
120
+
121
+ ```bash
122
+ hirify api call filters.preview --data '{"filters":{"search":"product manager"},"mode":"compact","per_page":20}'
123
+ ```
124
+
125
+ Inspect the cards and `meta.total`, refine when needed, and only then run `hirify vacancy search`
126
+ with the same criteria. Preview and search use the same search implementation.
127
+
128
+ `--json` gives `{"guide": "<text>"}`. The text is written for a model to read, so pass it through
129
+ rather than summarising it.
130
+
131
+ A server that does not serve the guide yet answers plainly: `this Hirify server does not serve the
132
+ filter guide yet.` Then the criteria have to come from the user, not from a guess.
133
+
134
+ ## vacancy read: one vacancy in full
135
+
136
+ ```bash
137
+ hirify vacancy read <slug>
138
+ ```
139
+
140
+ The card plus everything else the vacancy page shows: area, grade, skills, location, when it was
141
+ posted, the page address, and the description as text. This is the command that decides fit, and it
142
+ is deliberately cheap.
143
+
144
+ It costs one vacancy open from the daily allowance, and the same vacancy read again the same day
145
+ costs nothing. The output states whether an open was used and how many are left.
146
+
147
+ The last line before that says which way to apply:
148
+
149
+ - `Apply on Hirify: hirify vacancy apply <slug>` - the vacancy is hosted here.
150
+ - `Where to apply: hirify vacancy reveal <slug> (uses 1 reveal)` - it came from elsewhere, so the
151
+ user applies themselves. Take this from `vacancy read` rather than finding out from a refusal on
152
+ `vacancy apply`.
153
+
154
+ Contacts, the apply destination and where the vacancy came from are never in this answer. That is
155
+ what `vacancy reveal` is for.
156
+
157
+ With `--json`, `data.description` is HTML (`data.description_format` says so) and the text output is
158
+ the same content flattened for a terminal. `charged` and `quota` sit next to `data`.
159
+
160
+ Refusals: `there is no vacancy with that slug.`, and, when the day's opens are spent, `you have
161
+ opened as many vacancies today as the daily allowance covers.` - feeds and search still work then,
162
+ and so does any vacancy already read today.
163
+
164
+ ## vacancy reveal: where to apply
165
+
166
+ ```bash
167
+ hirify vacancy reveal <slug>
168
+ ```
169
+
170
+ Spends 1 reveal and returns the company, its LinkedIn page when known, and one or more
171
+ contacts: an address, a form URL, or a link. Revealing the same vacancy again returns the same thing
172
+ and spends nothing, so a repeat is safe. The output states whether a reveal was used and how many
173
+ are left.
174
+
175
+ Shortlist with `vacancy read` first. A reveal spent at random is spent.
176
+
177
+ ## vacancy apply: only on Hirify
178
+
179
+ ```bash
180
+ hirify profile list
181
+ hirify vacancy apply <slug> [--profile <id>] [--cover "<text>"]
182
+ ```
183
+
184
+ `profile list` lists what the user can apply with: `<profile_id> <name> [status · incomplete]`.
185
+
186
+ `vacancy apply` sends an application through Hirify. **Ask the user first, every time, and show
187
+ what you are sending.** It cannot be undone, and it counts against a daily allowance of its own:
188
+ `hirify account show` reports what is left, and `hirify account show --json` carries it as
189
+ `quota.apply` with `limit`, `used` and `remaining` as the server currently has them.
190
+
191
+ - `--profile` is required when the user has more than one profile. With exactly one, it is chosen
192
+ automatically. Never guess between several.
193
+ - `--cover` is optional. There is a length ceiling and the server owns it: if the letter is too
194
+ long, the answer says so. Write it from what the user told you and show them the draft first.
195
+
196
+ Answers:
197
+
198
+ - success: `Applied. Application <id>, status <status>.` Nothing follows up: the recruiter replies
199
+ where they choose to.
200
+ - `there is no vacancy with that slug.`
201
+ - a refusal in the server's own words, which covers archived, flagged, someone else's profile, and
202
+ **vacancies not hosted on Hirify**. For those, use `vacancy reveal` and let the user apply
203
+ themselves.
204
+ - `the application could not be sent right now.` means our side failed, not the user's data.
205
+
206
+ ## Saved searches and delivery
207
+
208
+ ```bash
209
+ hirify feed create "<name>" [--filters '<json>'] [--telegram|--no-telegram] [--webhook <id>]
210
+ hirify feed deliver <id> [--telegram|--no-telegram] [--webhook <id>|--no-webhook]
211
+ hirify webhook list
212
+ hirify webhook create "<name>" <url>
213
+ ```
214
+
215
+ These change the user's account. Propose, get a yes, then run them.
216
+
217
+ `--filters` takes the same criteria the site's filter form produces, as JSON, and the names come
218
+ from `hirify filter guide`. Omitting it saves a feed with no criteria, which means "send me
219
+ everything" and is legal.
220
+
221
+ `webhook create` answers with the endpoint and a **secret shown once**. Hand it to the user
222
+ immediately and tell them to store it: it signs every delivery and cannot be shown again.
223
+
224
+ ## feedback send
225
+
226
+ ```bash
227
+ hirify feedback send <bug|feature> "<title>" --body "<text>" [--vacancy <slug>]
228
+ ```
229
+
230
+ Both a title and a body are required, and the CLI says so before sending anything. Their lengths
231
+ are the server's rule, not the CLI's: too short or too long comes back as the server's own sentence
232
+ naming which. Ask the user before sending and send their words. The answer gives a ticket number,
233
+ or says there is no number yet. There is no page to open, nothing writes back to the user, and no
234
+ reply, fix or date is promised. Report that it was passed on and stop there.
235
+
236
+ Refusals: too many reports in a short time (with the wait in seconds), the channel being off, or the
237
+ report not being accepted.
238
+
239
+ ## api call: any capability by its id
240
+
241
+ ```bash
242
+ hirify api call <capability-id> [--data '<json>'] [--fields a,b] [--json]
243
+ ```
244
+
245
+ Invokes any capability Hirify lists in its manifest, by its id, and prints the answer. It is here so
246
+ that a job this CLI has no named command for is a detour rather than a dead end. The ids are the
247
+ ones the manifest publishes; the named commands above cover the common ones, and this reaches the
248
+ rest.
249
+
250
+ ```bash
251
+ hirify api call account.status
252
+ hirify api call vacancies.search --data '{"search":"go","per_page":5}'
253
+ hirify api call feeds.create --data '{"name":"Senior Go","filters":{}}'
254
+ ```
255
+
256
+ - Inputs go in `--data` as one JSON object. Each value is routed where the manifest places it: into
257
+ the path, the query string, or the body. A `--data` that is not JSON is refused before anything is
258
+ sent, and a capability the manifest does not list is named as unknown without a request being made.
259
+ - The answer is rendered compactly by default, so it reads without a parser: a vacancy card shows the
260
+ same shortlist fields `vacancy search` prints, and any other shape shows the fields the server
261
+ returned, one per line. `--fields a,b` narrows that to the fields you name.
262
+ - `--json` gives the raw canonical answer instead, refusals included, so what you parse is the
263
+ server's own payload rather than a sentence of ours. On a refusal the raw answer is printed and the
264
+ exit code is non-zero.
265
+
266
+ **Prefer a named command where one exists.** This one carries none of what they know: it will not
267
+ tell you that a call costs a reveal, and it will send a real application as readily as
268
+ `vacancy apply` would. The permission rules do not change: ask the user before anything that sends,
269
+ saves or configures.
270
+
271
+ ## Failure modes worth knowing
272
+
273
+ | Message | What it means | What to do |
274
+ |---|---|---|
275
+ | `you are not signed in yet` | no stored access | ask the user to run `hirify login` |
276
+ | `your sign-in is no longer valid` | the session expired past renewal | ask the user to run `hirify login` |
277
+ | `the key was not accepted (401)` | a manual key was revoked or truncated | new key from the account page |
278
+ | `no access (403)` | missing permission, or the plan does not cover agent access | sign in again, or check the plan |
279
+ | `you have no reveals left right now` | the reveal budget is spent | reading still works; `hirify account show` has what is left |
280
+ | `you have sent as many applications today...` | the daily allowance for applying is spent | reading and revealing still work; `hirify account show` has what is left |
281
+ | `you have opened as many vacancies today...` | the day's vacancy opens are spent | feeds, search and anything already read today still work |
282
+ | `too many requests in a short time` | asking faster than the API allows | wait the seconds it names, then carry on |
283
+ | `something went wrong on our side` | our fault, not the request | retry in a minute |
284
+ | an empty list from a filtered search | usually a criterion name or value that does not exist | check the name against what the server accepts, do not keep guessing |
285
+ | `the network seems to be unavailable` | no connection | retry |
286
+ | `hirify <noun> has no verb "..."` | a command name this CLI does not have | the message lists the verbs that noun takes; read it rather than guessing again |