Metadata-Version: 2.4
Name: hevn-cli
Version: 0.1.2
Summary: Command-line client for the HEVN backend API and MCP transfers.
License: MIT
License-File: LICENSE
Keywords: hevn,cli,fintech,payments,invoicing,mcp,stablecoin
Author: HEVN Team
Author-email: team@hevn.finance
Requires-Python: >=3.11,<4.0
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Dist: click (>=8.1.8,<8.2)
Requires-Dist: httpx (==0.28.1)
Requires-Dist: mcp (>=1.2,<2)
Requires-Dist: prompt-toolkit (==3.0.36)
Requires-Dist: python-dotenv (==1.2.2)
Requires-Dist: pyyaml (==6.0.3)
Requires-Dist: qrcode (==8.2)
Requires-Dist: questionary (==2.1.0)
Requires-Dist: rich (==13.9.4)
Requires-Dist: tomli-w (>=1.0,<2)
Requires-Dist: typer[all] (==0.15.1)
Project-URL: Homepage, https://github.com/hevn/hevn-cli
Project-URL: Repository, https://github.com/hevn/hevn-cli
Description-Content-Type: text/markdown

# HEVN CLI

Standalone command-line wrapper for the [HEVN](https://app.gethevn.com) backend API and MCP transfers.

> Requires an active HEVN account. Sign up at [app.gethevn.com](https://app.gethevn.com) before installing.

## Install

For end users:

```bash
pipx install hevn-cli
hevn login
hevn --help
```

Global install on macOS with `pip`:

```bash
python3 -m pip install --user hevn-cli
python3 -m site --user-base
```

Add the printed `bin` directory to your shell path. On most macOS installs this
is `~/Library/Python/3.11/bin` or `~/Library/Python/3.12/bin`:

```bash
echo 'export PATH="$HOME/Library/Python/3.12/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
hevn --help
```

Homebrew install, after a tap is published:

```bash
brew tap hevn/hevn
brew install hevn-cli
hevn --help
```

For the Homebrew tap, do not shell out to the system `pip install hevn-cli`.
Create a formula that installs the PyPI package into Homebrew's isolated Python
virtualenv:

```ruby
class HevnCli < Formula
  include Language::Python::Virtualenv

  desc "Command-line client for the HEVN backend API and MCP transfers"
  homepage "https://github.com/hevn/hevn-cli"
  url "https://files.pythonhosted.org/packages/source/h/hevn-cli/hevn_cli-0.1.0.tar.gz"
  sha256 "<sha256>"
  license "MIT"

  depends_on "python@3.12"

  resource "httpx" do
    url "https://files.pythonhosted.org/packages/source/h/httpx/httpx-0.28.1.tar.gz"
    sha256 "<sha256>"
  end

  # Add one resource block for each PyPI dependency, then install them together.
  def install
    virtualenv_install_with_resources
  end

  test do
    assert_match "HEVN backend CLI", shell_output("#{bin}/hevn --help")
  end
end
```

Before the package is published to PyPI, install from GitHub so `pipx upgrade`
can fetch newer commits:

```bash
pipx install "git+https://github.com/hevn/hevn-cli.git"
pipx upgrade hevn-cli
```

For local development:

```bash
poetry install
poetry run hevn --help
```

For local wheel smoke testing only:

```bash
poetry build
pipx install dist/hevn_cli-0.1.0-py3-none-any.whl
```

Local wheel installs are not a good long-term `pipx` install source because
`pipx upgrade hevn-cli` can only reinstall from that same local artifact.

## Publish

PyPI publishing is handled by the `Publish to PyPI` GitHub Actions workflow.
Run it manually from the `main` branch. The workflow runs lint, tests, and
`hevn --help` on Ubuntu, macOS, and Windows, then builds and publishes the
package once from Ubuntu.

The workflow uses PyPI trusted publishing. In the PyPI project `hevn-cli`,
configure a trusted publisher with GitHub owner `hevn`, repository `hevn-cli`,
workflow `.github/workflows/publish-pypi.yml`, and environment `pypi`.

## Environment

```bash
export HEVN_ENV="prod" # prod (default), dev, or local
export HEVN_API_KEY="hvn_..."
export HEVN_API_KEY_HEADER="X-Api-Key"
```

Optional:

```bash
export HEVN_BASE_URL="https://api.hevn.finance/api/v1"
export HEVN_SITE_URL="https://app.gethevn.com"
```

`hevn login` opens HEVN in the browser, creates or selects an app, issues an app
API key, and stores it locally with `X-Api-Key` as the app header. `Authorization`
is still supported for legacy bearer tokens and is sent as `Bearer <HEVN_API_KEY>`.
MCP transfer endpoints use the app API key as `X-API-Key`.
Use `HEVN_*` environment variables for CLI configuration.

Built-in environments:

| Env | Site URL | API URL |
| --- | --- | --- |
| `prod` | `https://app.gethevn.com` | `https://api.hevn.finance/api/v1` |
| `dev` | `https://app-beta.hevn.finance` | `https://dev-api.hevn.finance/api/v1` |
| `local` | `http://localhost:8081` | `http://localhost:8000/api/v1` |

You can also select the environment per command:

```bash
hevn --env dev account get
hevn --env local login
```

Clear saved CLI credentials:

```bash
hevn logout
```

## Connect AI coding agents (MCP)

`hevn mcp` exposes the whole CLI to MCP-speaking coding agents (Claude Code,
Codex, Cursor, Windsurf, Claude Desktop) so they can act on your HEVN account —
no per-agent setup, no copying instructions. Every CLI command becomes an MCP
tool, annotated with its danger level (reads auto-run; transfers and deletes are
flagged so the host asks for confirmation), and the agent guide ships as the
server's MCP instructions.

One command wires up every agent it finds on your machine:

```bash
hevn login        # the MCP server reuses this credential
hevn mcp install  # register hevn in every detected agent
```

Then restart the agent and ask it to, e.g., "check my HEVN balance".

```bash
hevn mcp list                       # show agents, detection, install state
hevn mcp install --client cursor    # target a specific agent (repeatable)
hevn mcp install --all              # also write configs for agents not detected
hevn mcp install --with-key         # embed HEVN_API_KEY in the config (portability)
hevn mcp uninstall                  # remove the hevn server from agent configs
hevn mcp serve                      # the stdio server itself (agents launch this)
```

By default no key is written into agent configs — `hevn mcp serve` reads your
stored `hevn login` credential like any other command. Use `--with-key` only
when you need a self-contained config (e.g. a different user or machine).

| Agent | Config |
| --- | --- |
| Claude Code | `~/.claude.json` |
| Claude Desktop | `claude_desktop_config.json` (OS-specific location) |
| Cursor | `~/.cursor/mcp.json` |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
| Codex CLI | `~/.codex/config.toml` |

## Introspecting the active API key

`hevn whoami` calls `GET /apps/me` and returns everything the backend knows
about the configured `X-Api-Key` in a single payload — no need to chain
`/user`, `/apps/{id}` and `/balance` yourself:

```bash
hevn whoami
hevn whoami --yaml
```

Response fields:

| Field | Description |
| --- | --- |
| `name` | The user's display name (`firstName lastName` or `entityName`). |
| `email` | The user's email. |
| `balance` | Onchain USDC balance of the user's primary smart wallet (the source of funds). |
| `spendLimit` | Remaining USDC the app may pull under its active SpendPermission. |
| `appId` | The owning `ApiApp.id`. |
| `appName` | The owning app's display name. |
| `scope` | List of route-tag scopes this key is allowed to call (values from `RouteScope`). |

Allowed `scope` values (lower-cased route tags — these are intersected
case-insensitively with the route's tags on every request):

```text
apps, apps-transfer,
balance, banks, cards, transactions, exports, merchant,
contracts, invoices, documents,
user, team, chat, devices, referrals, public,
mcp, xero,
admin, admin sso, kybagent, b2b, incorporate, 2fa,
auth, activity, tee, tee-local, utils, webhook
```

Unknown / legacy scope strings stored on an older app are silently dropped
from the response — callers only ever see values from this enum.

## Examples

```bash
hevn contacts list
hevn contacts list --yaml
hevn login
hevn whoami
hevn whoami --yaml
hevn account list --yaml
hevn banks list --all
hevn contacts new
hevn contacts new --type email --name "Vendor" --email vendor@example.com
hevn transfer contact <contact-id> 25 --memo "Thanks"
hevn transfer contact --contact-id <contact-id> --amount 25 --memo "Thanks"
hevn transfer contact --contact-id <contact-id> --amount 25 --yes --memo "Bank payout"
hevn transfer contact --contact-id <contact-id> --amount 25 --bank-account-id <bank-account-id> --yes --memo "Bank payout"
hevn transfer contact --contact-id <contact-id> --quote-id <quote-id> --memo "Bank payout"
hevn invoice list
hevn bills --yaml
hevn invoice get <invoice-id>
hevn invoice decline --invoice-id <invoice-id> --yes --yaml
hevn invoice new
hevn invoice new --contractor-email vendor@example.com --contractor-name Vendor --item "Consulting:1:100" --due-date 2026-06-01
hevn invoice upload-incoming --path ./invoice.pdf --contractor-email vendor@example.com --items '[{"name":"Consulting","quantity":1,"price":"100"}]'
hevn invoice batch --contract '{"contractId":"<contract-id>","period":0,"memo":"May payroll","items":[{"name":"Monthly services","quantity":1,"price":"5000"}]}' --yaml
hevn contracts list --yaml
hevn contractors list --yaml
hevn contracts preview --id <contract-id> --yaml
hevn contracts new --contractor-email contractor@example.com --document-id <document-id> --item '{"name":"Design","quantity":2,"price":"100"}' --period monthly --activation-at 2026-07-10 --yaml
hevn contracts generate --contractor-email contractor@example.com --type default_contractor --amount 1000 --currency USD --period monthly --activation-at 2026-05-01 --yaml
hevn contracts update --id <contract-id> --period monthly --activation-at 2026-07-10 --field 'paymentTerms=Payment on the 10th for the previous month' --yaml
hevn contracts payment-methods --id <contract-id> --payment-method '{"accountType":"email","email":"contractor@example.com"}' --yaml
hevn contracts --id <contract-id> approve --yaml
hevn hire --contractor-email contractor@example.com --job-title "Engineer" --scope-description "Full-time engineering work" --amount 5000 --currency USD --period monthly --start-date 2026-05-01 --yaml
hevn transfer --invoice-id <invoice-id> --memo "Invoice payment"
hevn deposit 100 usdc base
hevn deposit --amount 100 --currency usdc --chain base
hevn rate EUR
hevn rate --currency AED --yaml
```

Contract statuses:

```text
pending_approval_by_contractor
pending_approval_by_client
active
completed
cancelled
paused
```

`hevn contracts new` uploads an existing contract file/document id. It always
creates the contract with `status=active` and does not start signing. Use
`hevn contracts generate` only when HEVN should generate a new contract from a
template; generated contract types must start with `default_`.
When uploading a file, the CLI tries to infer the contract type from the file
name/content. Pass `--type <type>` to override the inference.

When an agent runs `hevn contracts new` from a contract file, it should parse
the document first and pre-fill as many flags as possible — contract type,
label, commercial terms (`--amount`, `--currency`, `--period`,
`--activation-at`, `--item`/`milestones[]`, `rateType`) and counterparty data
(email, address, tax id, bank requisites). It should also extract both party
names — pass them as `--field contractorName=...` and
`--field clientName=...`, and reuse the counterparty name in `--label`.

Crucially, the agent must decide **for every contract**, by reading the
document, which party is the client and which is the contractor — never assume
the current HEVN user always plays the same role. Many contracts will have the
current user as the **contractor** and the counterparty as the client; that is
just as common as the opposite. Look up the current user with
`hevn profile get --yaml`, match them against the parties in the document,
then pick the right email flag:

- If the current user is the **client** in the document → pass the
  counterparty's email as `--contractor-email <email>`.
- If the current user is the **contractor** in the document → pass the
  counterparty's email as `--client-email <email>`.

The email flag always identifies the **counterparty's** role, not the current
user's role. Ask the user only when the document does not contain the
counterparty's email; do not invent one.

`hevn hire` is a convenience alias for generating a `default_contractor`
contract.
Preview it with `hevn contracts preview --id <contract-id> --yaml`, then approve
with `hevn contracts --id <contract-id> approve --yaml`.

Contract creators can edit existing contract terms and invoice schedules with
`hevn contracts update`. Use `--activation-at` as the recurring invoice anchor
date; for example, `--period monthly --activation-at 2026-07-10` schedules the
monthly payment day on the 10th from July 10, 2026 onward.

## Contract templates

Use `hevn contracts new` for existing uploaded contracts. It always creates an
active contract and does not require signatures. Use `hevn contracts generate`
only for HEVN-generated `default_*` templates and normal approval/signing flow;
the CLI rejects non-`default_*` types for `generate`.

Supported `--type` values and user-supplied fields:

| Type | Use for | Required fields | Optional fields |
| --- | --- | --- | --- |
| `custom` | Existing uploaded agreement with invoice line items. | `currency`, `items[].name`, `items[].price` | `items[].quantity` |
| `contractor` | Existing uploaded independent contractor agreement inferred by `contracts new`. | `amount`, `currency`, `rateType` | `hours`, `taxId`, `jobTitle`, `scopeDescription` |
| `default_contractor` | Generated HEVN contractor agreement with default legal terms. This is the supported `contracts generate` type. | `amount`, `currency`, `rateType` | `hours`, `taxId`, `jobTitle`, `scopeDescription` |
| `service` | Existing uploaded services/consulting agreement inferred by `contracts new`. | `amount`, `currency`, `services` | `paymentTerms` |
| `employment` | Existing uploaded employment agreement inferred by `contracts new`. | `amount`, `currency`, `positionTitle`, `scope` | `paymentTerms` |
| `nda` | Existing uploaded mutual non-disclosure agreement inferred by `contracts new`. | `purpose` | `permittedDisclosures` |
| `vendor` | Existing uploaded vendor/supplier agreement inferred by `contracts new`. | `amount`, `currency`, `goodsOrServices` | `deliveryTerms`, `acceptanceCriteria`, `paymentTerms` |
| `milestone` | Existing uploaded project agreement billed by milestones inferred by `contracts new`. | `currency`, `projectName`, `scope`, `milestones[].name`, `milestones[].amount` | `milestones[].deliverables`, `milestones[].dueDate`, `paymentTerms` |
| `msa` | Existing uploaded master services agreement framework inferred by `contracts new`. | `servicesFramework` | `orderingProcess`, `paymentTerms` |

Profile/computed fields such as party names, addresses, effective date,
governing law, signatures, and document title are resolved by the backend or
collected during approval. Do not pass them as normal `--field` values.

## Contract migration guidance

When a user asks to move or import contracts or contractors into HEVN, load them
by creating a new active contract from the contract file rather than only adding
contractor records. For Deel migrations, first suggest that the user create a
Deel API token at
[app.deel.com/settings/developer/tokens/create](https://app.deel.com/settings/developer/tokens/create).

