# Use the Economico CLI


The Economico CLI is a REST client for a terminal or an agent without an MCP host.
It discovers operations and their flags from the server's authorized OpenAPI
document. It uses the same business permissions and command path as HTTP and MCP.

## Install and sign in

Use Node.js 24 or newer:

```sh
npm install -g @economico/cli
economico --version
economico login --server https://economi.co --local
```

Login opens the browser for OAuth approval with PKCE and a loopback callback.
`--local` stores the connection in the current project's `.economico/config.json`
and adds `.economico/` to that directory's `.gitignore`. Keep credentials out of
chat, shared files and version control. Approve the business and access yourself.

For your own agent identity, choose **Continue with AgentID** and follow the
[AgentID sign-in and signup procedure](/docs/authentication/#sign-in-as-an-agent-with-agentid).
Use your AgentMail inbox to authorize the pending sign-in, then return to the
same browser. Existing books require a membership grant; creating a Solo business
requires a separate human-owner signup approval and gives the agent bookkeeper
access. Complete the original OAuth flow before running CLI commands.

Use `login --no-browser` to print the authorization URL instead of opening it.
`login --port <port>` selects the callback port. A new user can create a business
in the browser during login; signup flags only prefill the form for review.
`economico login --help` lists those flags. `economico logout` removes stored tokens
from the selected configuration file; it does not delete the business.

Without a permanent installation, `npx -y @economico/cli@latest` runs the same CLI:

```sh
npx -y @economico/cli@latest login --server https://economi.co --local
npx -y @economico/cli@latest businesses list
```

## Select a business and discover operations

```sh
economico businesses list
economico --business example-sandbox tools
economico --business example-sandbox catalog list
economico --business example-sandbox catalog describe --name parties.create
```

Replace `example-sandbox` with a business slug returned by `businesses list`.
Every business invocation sends its own `--business`; there is no mutable current
business. The flag becomes `X-Economico-Business` on the HTTP request. A slug is an
identifier, not a grant of access. Use a disposable sandbox or isolated demo for
practice writes; never use the Economico production business, slug `economico`.

`tools` lists the operations this connection can discover for the selected
business. An operation ID becomes a tool and verb: `reports.run` becomes
`reports run`. Availability can change with permissions and the server catalog;
use discovery rather than assuming a fixed command tree.

```sh
economico --business example-sandbox reports run --help
economico --business example-sandbox commands execute --help --json
```

The first prints the operation's flags. `--help --json` prints its complete schema.
For commands, describe the named command separately: generic `commands execute`
help summarizes the envelope, not every command's input variant.

## Read a report

```sh
economico --business example-sandbox reports list
economico --business example-sandbox reports run \
  --kind balance_sheet --currency USD --as_of 2026-07-31
economico --business example-sandbox reports run \
  --kind balance_sheet --currency USD --as_of 2026-07-31 --human
```

JSON is the default and preserves the report contract. `--human` formats supported
financial statements and summarizes other results. Reports and previews do not
create entries. Their descriptions distinguish recorded books from calculations
based on supplied assumptions. Keep native currencies and date windows explicit.
The [report reference](/docs/report-reference/) explains each report's parameters
and how to interpret its result.

## Submit a command and check what changed

Read the [command reference](/docs/command-reference/) and the live description
before sending a write. This example creates a fictional counterparty in a
disposable sandbox; it does not post money:

```sh
economico --business example-sandbox catalog describe --name parties.create
economico --business example-sandbox commands execute \
  --name parties.create \
  --idempotency_key cli-example-vendor-1 \
  --effective_at 2026-07-01T00:00:00Z \
  --input '{"partyId":"pty_cli_example_vendor","name":"CLI Example Vendor","categories":["vendor"]}'
```

`--input` is the command-specific input object. `--name`, `--idempotency_key` and
`--effective_at` belong to the outer envelope. Use a stable source identity and
real evidence for actual bookkeeping, and keep exact minor-unit amounts as
strings. Creating a party is different from receiving a document, recording an
invoice, recording a completed payment or recognizing revenue.

On acceptance, inspect `result` and the returned event IDs and CIDs. Retain the
`commandId` and any domain identifiers returned by the command. To recover the
receipt, substitute the actual returned command ID:

```sh
economico --business example-sandbox commands get --id COMMAND_ID
```

Replay the same intent with the same key to recover its original receipt;
`replayed` identifies a replay. Changing the command or input under an accepted
key is an idempotency conflict. A domain `no_change` outcome has no persisted
receipt. Some commands also succeed with `events: []` and return a transient
`commandId` and result without storing a receipt. Looking up that ID can return
null; retain the result and verify the affected record. Retrying such a command
can re-evaluate current state instead of replaying a stored receipt. Check the
affected records or reports before moving to the next action.

## JSON files, stdin and field types

Field flags use the schema's exact spelling, including underscores. String
fields stay strings; booleans use `true` or `false`; numeric fields use JSON
numbers; objects and arrays take JSON. Money remains an integer string in a
named unit, even if it looks like a number.

Use `--args` for an entire JSON request object:

```json
{
  "name": "parties.create",
  "idempotency_key": "cli-example-vendor-1",
  "effective_at": "2026-07-01T00:00:00Z",
  "input": {
    "partyId": "pty_cli_example_vendor",
    "name": "CLI Example Vendor",
    "categories": ["vendor"]
  }
}
```

Save this as `command.json`, or pass equivalent JSON on stdin:

```sh
economico --business example-sandbox commands execute --args @command.json
cat command.json | economico --business example-sandbox commands execute --args -
```

These are alternative ways to send the same intent, with the same key. Do not
invent a fresh key just to retry a failed response. Flags can supplement `--args`,
but duplicate fields are refused. Unknown fields are refused too.

## Upload a source document

When the operation advertises multipart upload, `--file` sends exact local bytes:

```sh
economico --business example-sandbox documents submit \
  --file invoice.pdf \
  --input '{"kind":"source_document","title":"Vendor invoice"}' \
  --idempotency_key vendor-invoice-123 \
  --effective_at 2026-07-01T00:00:00Z
```

Omit `input.contentBase64` when using `--file`. The upload limit is up to 10 MiB;
a document kind may allow less. The client allows two minutes for an upload and
30 seconds for other calls; the server separately requires upload transfer to
finish within 30 seconds. Receiving the source preserves evidence; it does not
classify an expense or post its economics by itself.

## Errors and retries

Errors go to stderr and the process exits nonzero. A command is not automatically
replayed after a network failure. The client can refresh once after a `401` and
retry a `503 busy` with `Retry-After`, because the server did not start that
request. Other refusals require the caller to inspect the error and fix its cause.

After a lost response, recover the receipt or retry the same intent and key.
Never switch business, widen permissions or choose a new key merely to get past
a refusal. Browser-only actions require the signed-in human rather than a CLI
workaround. See [request and recovery rules](/docs/api/) for HTTP errors.

## Configuration and agent use

The configuration file is selected in this order:

1. `ECONOMICO_CONFIG_FILE`, when explicitly set.
2. The nearest trusted ancestor's `.economico/config.json`.
3. `$XDG_CONFIG_HOME/economico/config.json`, normally
   `~/.config/economico/config.json`.

Config files use mode `0600`. Ancestor discovery does not walk above the user's
home directory and, on Unix, ignores files the current user does not own.
`ECONOMICO_API_URL` overrides the stored server URL. Credentials belong to the
server that issued them; sign in again when changing servers.

Agents should parse JSON stdout, inspect stderr and exit status, discover the
authorized catalog, and name the business on every invocation. Ask the user to
complete interactive login; never ask for tokens in a prompt. This guide's
[Markdown mirror](/docs/cli/index.md) and the [agent execution map](/docs/agents/)
provide the same workflow without requiring HTML rendering.


