Hyreflow

CLI Concepts

The hyreflow CLI — a single-file JavaScript bundle that turns commands into metered engine calls.

The hyreflow CLI is a thin client. It holds no provider keys — every command is an authenticated HTTPS call to the engine, which resolves the key (managed or BYOK), runs the adapter, and meters credits. Install it with the quickstart one-liner.

hyreflow --help          # top-level command groups
hyreflow                 # bare invocation → overview, not an error

Auth

hyreflow auth login                  # browser sign-in (claims a token, no paste)
hyreflow auth wait [--timeout 120] [--json]   # finish a pending sign-in (no-op if already connected)
hyreflow auth login --token hf_live_xxx [--api-url https://recruit.hyreflow.ai]   # CI / manual token
hyreflow auth logout
hyreflow config show                 # current token + api-url

The browser flow is preferred — it claims a token without a paste and seeds your +25 starting credits. auth login opens your browser and, on an interactive terminal, waits for you to approve. In a headless/agent context (no TTY) it prints the sign-in link and returns so nothing hangs — approve the link, then hyreflow auth wait completes the connection (--wait auto|yes|no overrides that auto-detection). If a wait times out, the sign-in stays pending; hyreflow auth status reprints the link and the command to resume.

--timeout 0 checks once and returns instead of waiting, and --json reports the result as one line ({"connected": false, "status": "pending", "authorization_url": "…"}) — together they let an agent that can't run a long-lived blocking command poll on its own schedule.

Tools

Discover and run any single tool/method directly. Never guess params — read the callable surface first.

hyreflow tools list                      # every tool (single providers + waterfalls)
hyreflow tools get <tool> [method]       # method contract: http, path, params, cost
hyreflow tools execute <tool> [method] --payload '{...}'|@payload.json|- [--dry-run]

Every flag that takes JSON (--payload, --steps, --arg, --job, --candidates, --with) also accepts @FILE to read the JSON from a file and - to read it from stdin. Both carry no shell quoting at all, which is the reliable way to pass JSON from Windows PowerShell — quote the @FILE form there so PowerShell doesn't read the @ as a splat:

hyreflow tools execute people_search --payload "@payload.json" --dry-run
'{"titles":["CTO"],"limit":5}' | hyreflow tools execute people_search --payload -

A single-provider call (tools execute apollo search_people) hits one vendor. A waterfall tool (tools execute people_search) falls back across vendors and charges only on a usable result — except a public-web search step, which is charged per request. For bulk CSV work, use enrich rather than looping tools execute row by row.

Capabilities (waterfalls)

The high-level verbs are first-class tools — each runs a multi-provider waterfall and charges only on a usable result.

hyreflow tools execute people_search --payload '{"titles":["CTO"],"limit":N}'
hyreflow enrich --input <csv|ds_id> [--output out.csv] [--rows 0:1] \
  --with '{"alias":"email","tool":"<capability>","payload":{...}}'
hyreflow qualify --job @jd.txt --candidates @candidates.json   # hyreflow-only: score enriched candidates

Capabilities: people_search, email_enrichment, personal_email, linkedin_profile (a LinkedIn URL → that person's normalized employment history). Run linkedin_profile on a pool before you qualify it: a sourcing row carries the current title, employer and location only, and scoring reads the dated work history — qualify refuses a batch in which no row has one (--allow-thin-profiles scores it anyway, on the sourcing fields), and reports per candidate whether it was scored on work_history or title_only. Sourcing (people_search) runs via tools execute; enrichment via enrich, which reads its rows from --input (a CSV path or a ds_… dataset id) and applies one --with step per capability; --rows is a row RANGE (e.g. 0:1) for piloting, not a file. {{column}} in a payload string is filled from the row. Rows in one enrich run are processed in parallel, so a batch takes about as long as its slowest row rather than the sum of all rows.

hyreflow enrich --input leads.csv --estimate --with '{"alias":"email","tool":"email_enrichment","payload":{}}'
hyreflow enrich --input leads.csv --yes --with '{"alias":"email","tool":"email_enrichment","payload":{}}'

--estimate returns the worst-case credit cost and balance check without running. Live runs show the estimate and ask for confirmation (TTY) unless you pass --yes; if the workspace balance is insufficient, the CLI prints the required credits and a checkout link.

A run that fails upstream exits non-zero, as does one whose response didn't come from the engine at all — a proxy or captive portal answering with its own page, whatever status it carries. If --output was given, the CLI attempts to recover the already-charged dataset to that path before exiting non-zero, so a script or agent loop can tell success from failure by the exit code alone.

A live run prints each capability's provider chain before it starts (email_enrichment: prospeo → …) and an elapsed-seconds heartbeat while the batch is in flight, so a long run is visibly working. The run summary ends with provider_stats — a per-provider tally of every step the waterfall reached, keyed by outcome (hit, miss, skip, …), which the CLI also prints as a short table.

Provenance columns

Each alias gets sibling columns in the dataset and the exported CSV, written for every row (including misses), so they're safe to depend on, sort, or filter on. For an alias email:

columnholds
emailthe enriched value (empty when nothing was found)
email_sourcewhich provider step supplied the value — a capability/waterfall step names the winning provider step, e.g. prospeo.find_email; a plain --with step against a flat tool names the tool itself, e.g. apollo_search_people — empty when there's no value
email_statushit, miss, skip (no key for that provider), error, or a more specific reason such as no_identifier / no_provider / auth_error
email_verifiedwhether the value was verified, for capabilities that verify (email enrichment); empty otherwise
email_chargedcredits charged for that alias on that row

A row that found nothing exports an empty email cell — email_status says why. The four provenance columns for an alias are allocated as one group. If the input already has a column named some of email_source, email_status, email_verified, email_charged, all four are suffixed together (email_source_2, email_status_2, email_verified_2, email_charged_2), leaving your own column untouched. If the input has all four — an earlier Hyreflow export being enriched again — they're reused in place, so re-running a file doesn't accumulate a new group every time. The whole input is scanned for those names, not just the first rows, so a column that only appears deep in a large file still counts.

Datasets

A dataset (ds_…) is a stored result table — sourcing output, an enrich run, etc. — that any enrich --input ds_… can read back without re-fetching. Inspect and export them:

hyreflow dataset list [--session]              # all datasets (or just this session's)
hyreflow dataset show <ds_id>                  # metadata: columns, row count, source
hyreflow dataset head <ds_id> -n 10            # first N rows
hyreflow dataset rows <ds_id> [--offset 0] [--limit 50]
hyreflow dataset download <ds_id> --out out.csv
hyreflow dataset delete <ds_id>

Sessions (Playground narration)

Publish a plan so the user can watch progress live in the Playground. Mandatory before any credit call — without it the UI shows nothing.

hyreflow session start --steps '["Recon","Pilot search","Approval gate","Full pull","Enrich","Deliver"]' \
  --user-prompt "find all people at Acme"
hyreflow session start --steps "@steps.json" --user-prompt "find all people at Acme"   # PowerShell-safe
hyreflow session update --index 0 --status running     # pending|running|completed|error|skipped
hyreflow session status --message "aiark returned 0 — falling back to apollo" --step-index 1
hyreflow session output --csv hyreflow/data/<slug>/<slug>.csv --label "Acme employees"
hyreflow session limit --dollars N                     # raise/lower this session's own spend cap
hyreflow session limit --clear                         # remove this session's cap entirely
hyreflow session show
hyreflow session end                                   # close the run — later calls stop counting toward it

Every credit call you make while a session is active is attributed to it, so the Playground's spent pill reflects that run's cost. A session starts with the workspace's default per-session cap (hyreflow billing session-limit); session limit overrides that cap for this one session only, leaving the account default and every other session untouched — clearing it makes the session uncapped rather than reverting to the default. Run session end when the run is over: it closes the session so later commands no longer count toward its spent total or per-session spend cap.

Every session subcommand except start, plus playground open, accepts --session-id ses_… to name its session explicitly rather than acting on whichever session the CLI currently has active — this is what lets a detached or background shell narrate into a run it didn't start. Without the flag, the CLI resolves the session from the HYREFLOW_SESSION_ID environment variable (when it holds a ses_… id), falling back to the session recorded by the most recent session start. A command that can't resolve a session either way prints why and exits non-zero, so a script or agent loop reading the exit code never mistakes a session it failed to reach for one it updated.

Don't re-post --steps just to finish a run — it replaces the plan. Use session update to mark steps done. Re-post --steps only if the plan structure truly changes.

Billing

hyreflow billing balance                                    # remaining credits
hyreflow billing limit [--set CREDITS | --clear]            # rolling 30-day workspace spend cap
hyreflow billing session-limit [--set USD | --clear]        # default per-session spend cap for new sessions

billing session-limit sets the dollar cap every new session starts with; it doesn't touch a session that's already running. To override or clear the cap for one running session, use hyreflow session limit (see Sessions above).

Workspace

A workspace is the account — credits, keys, and data all belong to it, and you can belong to several. The CLI keeps one active workspace and scopes every call to it; switching needs no re-login.

hyreflow workspace list                 # workspaces you belong to (active is marked)
hyreflow workspace create <name>        # create a new workspace and switch to it
hyreflow workspace status               # active workspace + the full list
hyreflow workspace switch <slug|n|id>   # switch active workspace (omit the arg to list choices)

list and status print a table — the # is the switch index and active marks the current workspace:

┌───┬─────────────────┬─────────────────┬───────┬─────────────────┬────────┐
│ # │ slug            │ name            │ role  │ id              │ active │
├───┼─────────────────┼─────────────────┼───────┼─────────────────┼────────┤
│ 1 │ acme-recruiting │ Acme Recruiting │ admin │ ws_11c2d3e4f5a6 │ ●      │
└───┴─────────────────┴─────────────────┴───────┴─────────────────┴────────┘
Logged in as: [email protected]

The slug (acme-recruiting) is the handle — a lowercase, dash-separated form of the name, and what you pass to switch. switch also takes the # from that table or a ws_… id; workspace names are not matched.

A switch is remembered per host and applies to every command that follows — sourcing, enrichment, sessions, workflows, datasets and billing all act on (and bill) the workspace you switched to. hyreflow auth status shows it with a (switched) marker so it's clear you're not on the workspace your login created:

Workspace: Acme Recruiting (switched)
Workspace slug: acme-recruiting
Org ID: ws_…
Balance: 475 cr

See Teams & Workspaces for the account model and invites.

BYOK (bring your own key)

Add your own provider key and that provider's calls run against your account — free on Hyreflow, you pay the vendor directly. The key is stored server-side and never leaves the engine.

hyreflow byok set <provider> --api-key <key>   # add / replace your key for a provider
hyreflow byok list                             # providers you have keys for
hyreflow byok test <provider>                  # verify the key works
hyreflow byok disable <provider>               # pause the override (keeps the key)
hyreflow byok enable <provider>                # resume a paused override
hyreflow byok remove <provider>                # drop the key entirely

Once set, a BYOK provider jumps to the front of any waterfall it belongs to. See Credits & Billing for how BYOK affects charges.

Cloud workflows

workflows are saved pipelines that Hyreflow runs for you on the engine (metered), on a schedule, a webhook, or on demand. Author a definition, publish it, then run it.

hyreflow workflows apply --file flow.json [--publish]    # create/update a definition
hyreflow workflows list
hyreflow workflows get <workflow>
hyreflow workflows call <workflow> --payload '{...}' [--mode live|dry_run|smoke_test] [--tail]
hyreflow workflows runs --workflow-id <id>               # run history
hyreflow workflows tail --workflow-id <id> --run-id <id> # follow a live run
hyreflow workflows lint --file flow.json                 # validate before applying

Skills & maintenance

hyreflow skills install [--api-url ...] [--quiet]
hyreflow quick-setup [--yes]
hyreflow quickstart [--no-browser]
hyreflow telemetry [on|off|status]
hyreflow update

skills install unpacks the four packages from /api/v2/skills/bundle to ~/.agents/skills/<name> and links them into the skills directory of every supported agent found on the machine (Claude Code's ~/.claude/skills, Hermes Agent's ~/.hermes/skills, …). Any other agent with its own skill installer can pull the same packages straight from the public catalog at https://recruit.hyreflow.ai/.well-known/skills/index.json. Each entry there is consumable two ways — a files list served as individual text files, or one archive with a SHA-256 digest — so an installer takes whichever it expects.

Agents that keep separate profiles, each with its own skills directory, get a link in every profile — ~/.hermes/profiles/<name>/skills alongside the top-level one — so the skills are there whichever profile you launch. Because all of them point at the single copy in ~/.agents/skills, one refresh updates every profile at once. A profile you create later picks them up on your next hyreflow update.

One command to a working install

npm install -g hyreflow
hyreflow setup

hyreflow setup runs the whole first-run sequence and reports which step it's on: it checks the host, installs the agent skills, opens your browser to sign in, and confirms the workspace and credit balance.

It's resumable — browser approval happens on your time, so if you haven't approved yet it tells you so and stops. Re-run it and it finishes the sign-in already in flight rather than starting a new one, so the link you have open stays valid. Running it on a working install is a no-op.

For an agent driving the install, hyreflow setup --json reports the same thing as a phase machine (cli · skills · auth · verify) plus complete, authorization_url, and the command to re-run. --no-browser prints the sign-in link instead of opening one.

If a phase fails, the envelope also carries failed_phase (which of the four stopped it) and retry ({phase, command, automatic} — the exact command to re-run and whether it's safe to run automatically), and complete is false whenever failed_phase is set. Run retry.command once — setup resumes at the failed phase and keeps every phase that already completed rather than starting over.

The one-line installer installs the skills directly. An npm install lands the binary alone — the package runs nothing at install time, so it installs the same way under --ignore-scripts and behind a registry proxy that refuses scripted packages. hyreflow setup then installs the skills as one of its phases, and hyreflow auth login installs them too if they're still missing; hyreflow skills install does it on its own at any time. Set HYREFLOW_NO_SKILLS=1 to skip skills entirely, for CI and image builds.

hyreflow update upgrades the binary you actually run

hyreflow update installs into the same place the running CLI came from. For an npm install that's the npm prefix the running package lives in, so the hyreflow on your PATH is the one that moves — not whichever prefix npm happens to default to on that machine.

An install that didn't come from npm moves onto npm the first time you run update: it installs the published package, clears the old launcher out of the way so it can't shadow the new one, and every later update goes through npm from there. That switch needs Node 18+ on the machine — without it, update tells you what to install and leaves your working install exactly as it was.

It then proves it: after installing, it runs the hyreflow your shell resolves and compares its version against the target. If more than one install is present and the one on your PATH is behind, update says so, upgrades that install too, and re-checks — nothing to uninstall by hand. If the version still doesn't match, it reports the mismatch and names the install that's holding the old version instead of reporting success.

Because two installs shadow each other silently, hyreflow auth status and hyreflow update --check both name every install they can see on your PATH with its version (installs in hyreflow update --check --json).

Whoever installed the skills updates them

Two routes in, and each one owns keeping its own copy current:

  • Installed by hyreflowhyreflow update refreshes them. It compares the content hash from /api/v2/versions against your local copy and re-unpacks only on a change; hyreflow auth status prints sync needed when you're behind.
  • Installed by your agent (its own skill installer, a plugin marketplace, or a profile you cloned — cloning copies the files rather than the link) — that installer owns them, and hyreflow update deliberately won't touch them: they're real files in your agent's own directory, so replacing them would fight whatever put them there. Re-run that installer to update.

hyreflow skills install and hyreflow auth status both name any packages in the second category, so you can see at a glance which ones hyreflow update covers. To hand a package over to hyreflow, delete your agent's copy and run hyreflow skills install.

skills install also reports, per agent, which packages it linked and which it couldn't. When what sits at a package's target path in your agent's skills directory isn't a loadable package, or that directory can't be written to, your agent ends up without it. The usual cause is a leftover directory from an earlier install with no readable SKILL.md in it; delete that directory and re-run hyreflow skills install to pick the package up.

Both routes publish the same version number — skills.sha256 in /api/v2/versions, and version in the catalog index — so any installer can tell whether what it holds is current.

Telemetry is on by default. A run trace records which tool ran, which provider served it, timing and outcome (personal data redacted), and the CLI version that made the call — along with the ask that started the run, so a trace reads as your request followed by the tools it drove. That's what lets us answer "why did this run do that?" when you report a problem. The ask is the prompt you typed, not the whole conversation: no agent replies, no other tool calls.

Opt out any time with hyreflow telemetry off, or set HYREFLOW_TELEMETRY=0 for CI; the setting is stored per API host and hyreflow telemetry status prints it. Opting out never changes results or billing, and the run itself is unaffected either way.

That setting is per install, covering the calls this machine makes. A workspace can also have recording pinned on or off for the entire workspace — a support or debugging arrangement we set up with you. A workspace-level pin takes precedence over the local setting, and telemetry status reads only the local one, so it can print off while a pin is recording. Ask us and we'll tell you what your workspace is set to, or clear it.

Output convention

Write artifacts to hyreflow/data/<slug>/<slug>.csvnever /tmp/. Register any CSV you produce outside enrich with session output so it shows up in the Playground UI.

On this page